Простий сервер TCP


104

Напишіть програму або функцію, яка прослуховує вхідний трафік TCP на порт N. Він пропонує просту послугу: він обчислює суму полів IP-адреси вхідного з'єднання та повертає.

Програма або функція зчитує ціле число N з аргументів або stdin. Він прослуховує вхідні TCP-з'єднання на порт N. Коли хтось підключається до цього порту, програма обчислює суму своїх полів IP-адреси та відправляє його назад клієнтові з відключенням нового рядка та закриває з'єднання.

  • Номер порту N - дійсний порт, а 2 10 <N <2 15
  • Новий рядок може бути \nабо\r\n
  • Ви можете використовувати або IPv4, або IPv6. Оскільки адреси IPv6 записуються у шістнадцятковій формі, потрібно також надати результат, наприклад, у тому ж форматі 2001:0db8:0000:0042:0000:8a2e:0370:7334 => 12ecd.

Це . Застосовуються стандартні правила та лазівки.

Приклад

Ви запускаєте свій сервер за допомогою ./server 1234. Тепер сервер працює і чекає з'єднання на порту 1234. Потім клієнт з 127.0.0.1підключається до вашого сервера. Сервер виконує простий розрахунок: 127+0+0+1 => 128і посилає результат до клієнта (з задньої нового рядка): 128\n. Потім сервер закриває з'єднання і чекає наступного клієнта.

Таблиця лідерів

var QUESTION_ID=76379,OVERRIDE_USER=20569;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>


1
Чи дозволено використовувати inetd / xinetd чи подібні?
Цифрова травма

91
Мені це подобається, оскільки це проблема в гольфі, в якій мови для гри в гольф навряд чи будуть дуже хорошими.
isaacg

9
Мало того, що дивно, що TCP-сервер, мабуть, дуже проста програма для написання, я досконало налаштований на те, що він отримує гольф для задоволення. Я просто повернусь до боротьби з FizzBuzz, як імбецил.
MonkeyZeus

17
@isaacg Це лише час, коли хтось знайде TCP-сервер, вбудований в Mathematica
Downgoat

3
@MonkeyZeus Якщо чесно, ви не побачите тут жодного хорошого сервера TCP. Зробити надійний масштабований сервер TCP, який добре обробляє всі тонкощі TCP (і ваш протокол програми), трохи складніше: D Хоча це, безумовно, допомагає, що протокол надзвичайно простий - вам навіть не потрібно читати потік, щось що я бачив розбиті на занадто багато серверів TCP, щоб рахувати: D
Луаан

Відповіді:


57

Bash + netcat + ss +…, 65 60 символів

nc -lp$1 -c'ss src :'$1'|awk \$0=\$5|tr .: +#|bc'
exec $0 $1

Несерйозне рішення, просто цікаво про цю можливість.

Завдяки:

  • ніндзя за пропозицію awkфільтра на основі (-5 символів)

Проба зразка:

(термінал 1)

bash-4.3$ ./ip-reduce.sh 8080

(термінал 2)

bash-4.3$ nc localhost 8080
128

bash-4.3$ telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
128
Connection closed by foreign host.

У Ubuntu ви можете отримати ncз netcat-традиційних (ні, netcat-openbsd не є добрим) та ssз iproute2 .


22
Чому ти кажеш, що це не серйозне рішення? Поки це працює, як очікувалося, я не бачу причин, чому це не слід вважати серйозним. Це також найкоротший на сьогодні досить значний запас.
Алекс А.

Найбільше занепокоєння з цього приводу з’явилося під час обговорення з @JesseSielaff, коли я дізнався, що в системах з налаштованим IPv6 інформація про сокет може бути відформатована по-різному. Немає такої системи для її перевірки. Для чого я думаю, чи було б правильніше перетворити це на CW.
манатура

3
Я розумію специфікацію, що ви повинні підтримувати IPv4 або IPv6, а не обидва. Тому я думаю, що поки це працює для IPv4, не підтримуючи IPv6 не має значення.
Алекс А.

1
@AlexA. Принаймні, я думаю, моє запитання так говорить. Чи варто це уточнити?
Ганнес Карппіла

@HannesKarppila, ваше питання зрозуміле. Можлива проблема полягає в тому, що моє рішення може вимагати, щоб операційна система була налаштована певним чином, щоб мати змогу запускатися. Тож я переживаю, тому що він може вийти з ладу, якщо налаштований IPv6, незалежно від того, я обробляю його чи ні. Хтось, хто налаштував IPv6, міг це точно сказати…
манатура

23

C #, 284 283 282 278 274 254 байт

class A{static int Main(string[]a){var b=new System.Net.Sockets.TcpListener(int.Parse(a[0]));b.Start();for(;;){var c=b.AcceptTcpClient();var d=c.Client.LocalEndPoint.Serialize();new System.IO.StreamWriter(c.GetStream()).WriteLine(d[4]+d[5]+d[6]+d[7]);}}}

Класичний приклад базового сервера C # TCP. Тестування:

Термінал 1:

$ ./Q76379.exe 1029

Термінал 2:

$ telnet localhost 1029
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
128
Connection closed by foreign host.

Firefox:


7
Ви можете зберегти 1 байт, використовуючи int Mainзамість void Main. Оскільки програма ніколи не повертає, компілятор не вимагає returnзаяви.
рознагул

І ні, це не протікає. Це насправді досить детерміновано щодо вивільнення ресурсів. Крім того, аргумент до Startнеобов’язкового, збереження іншого символу.
Луань

@Luaan Так, це залишилося від налагодження.
LegionMammal978

Крім того, ви можете використовувати usingна TcpClient, що врятує вас ще три символи (використовуйте {}від з for), і робити те ж саме з the, StreamWriterслід зберегти ще один.
Луань

@Luaan Мені потрібно явно Flushце StreamWriterзробити, щоб воно працювало належним чином.
LegionMammal978

22

Linux ELF / x86, 146 байт

00000000  7f 45 4c 46 01 00 00 00  5a 0e 00 00 5a 5e eb 10  |.ELF....Z...Z^..|
00000010  02 00 03 00 0c 50 eb 10  0c 50 eb 10 04 00 00 00  |.....P...P......|
00000020  5e 53 43 53 52 89 e1 b0  66 3d 20 00 01 00 cd 80  |^SCSR...f= .....|
00000030  97 55 6b ed 0a 01 c5 ac  2c 30 79 f6 43 0f cd 01  |.Uk.....,0y.C...|
00000040  dd 55 89 e1 6a 10 51 6a  10 51 57 89 e1 b0 66 cd  |.U..j.Qj.QW...f.|
00000050  80 43 43 b0 66 cd 80 01  64 24 08 89 e1 43 b0 66  |.CC.f...d$...C.f|
00000060  cd 80 89 c1 93 8d 74 24  1b 99 fd ac 01 c2 e2 fb  |......t$........|
00000070  89 f7 b0 0a aa 91 92 f6  f1 86 c4 04 30 aa 42 c1  |............0.B.|
00000080  e8 08 75 f3 42 89 f9 41  b0 04 cd 80 b0 06 cd 80  |..u.B..A........|
00000090  eb c9                                             |..|
00000092

Включає 52-байтовий заголовок ELF, 32-байтний заголовок програми, 111 байт програмного коду + 3 байти коду для пропускання навколо заголовків.

Інформація про те , як створювати крихітні ELF виконуваних файлів можна знайти на сайті Breadbox «s " вихорі Підручник по створенню Really крихітний ELF Виконувані для Linux " .

Linux / i386 використовує socketcall(2)мультиплексний системний виклик, який приймає в ebxконкретному сокетному дзвінку ( SYS_*макроси з /usr/include/linux/net.h) та ecxвказівнику на область аргументів вихідного бібліотечного виклику.

Деякі речі, зроблені для того, щоб виконати маленький виконуваний файл:

  • Він передбачає, що регістри мають нульове значення при введенні, що робить Linux, але це не вимагає стандарту ELF (єдина вимога полягає у тому, що в EDXточках входу до функції завершення (корисно для виконуваних файлів, завантажених динамічним лінкером) або NULL).
  • Він передбачає, що при запуску (як правило, оболонкою) єдиними дескрипторами відкритого файлу є 0, 1 і 2. Що означає, що розетка для прослуховування буде fd 3, а прийнятий сокет буде fd 4.
  • Він передбачає, що існує рівно два аргументи (включаючи argv[0]).
  • Те ж місце в стеку повторно використовується для дзвінків bind(2), listen(2)і accept(2).
  • Для того, щоб перескакувати через phentsizeта phnumполе, байти предваряются, перетворюється в CMPоперацію , яка приймає phentsizeі phnumполе , як безпосередні (трюк безсоромно вкрадено з розчину Breadbox до 123 в анархії гольфах ).
  • Операції з рядком x86 LODS(завантаження в індекс джерела акумулятора та збільшення / зменшення) та STOS(зберігання з індексу призначення накопичувача та збільшення / зменшення) підходять для короткого коду.
  • XCHG EAX, regє 1-байтним порівняно з MOV EAX, reg, який займає 2 байти.
  • CDQ/CLTD(вхід-розширення EAXна EDX:EAX) може використовуватися як 1-байтовий спосіб нульової EDXреєстрації.
  • BSWAPкорисна для реалізації htons().

Джерело Nasm:

BITS 32                                         ;
                                                ;   ELF HEADER    --   PROGRAM HEADER
; ELF HEADER                                    ; +-------------+
DB 0x7f,'E','L','F'                             ; | magic       |    +--------------------+
                                                ; |             |    |                    |
; PROGRAM HEADERS                               ; |             |    |                    |
DD 1                                            ; |*class   32b | -- | type: PT_LOAD      |
                                                ; |*data   none |    |                    |
                                                ; |*version   0 |    |                    |
                                                ; |*ABI    SysV |    |                    |
DD 0xe5a        ; offset = vaddr & (PAGE_SIZE-1); |*ABI vers    | -- | offset             |
                                                ; |             |    |                    |
entry:  pop     edx     ; edx = 2 (argc)        ; |*PADx7       | -- | vaddr = 0x10eb5e5a |
        pop     esi     ; discard argv[0]       ; |             |    |                    |
        jmp     short skip                      ; |             |    |                    |
DW 2                                            ; | ET_EXEC     | -- |*paddr LO           |
DW 3                                            ; | EM_386      | -- |*paddr HI           |
DD 0x10eb500c                                   ; |*version     | -- | filesz             |
DD 0x10eb500c                                   ; | entry point | -- | memsz              |
DD 4                                            ; | ph offset   | -- | flags: RX          |
                                                ; |             |    |                    |
skip:   pop     esi     ; esi = argv[1]         ; |*sh offset   | -- |*align              |
socket: push    ebx     ; default protocol (0)  ; |             |    |                    |
        inc     ebx                             ; |             |    |                    |
        push    ebx     ; SOCK_STREAM (1)       ; |             |    |                    |
        push    edx     ; AF_INET (2)           ; |*flags       |    +--------------------+
        mov     ecx, esp                        ; |             |
        mov     al, 0x66                        ; |*ehsize      |
DB 0x3d         ; cmp eax,0x10020               ; |             |
DW 32                                           ; | phentsize   |
DW 1                                            ; | phnum       |
                                                ; |             |
        int     0x80    ; socket(2, 1, 0)       ; |*shentsize   |
        xchg    edi, eax; edi = sockfd, eax = 0 ; |*shnum       |
        push    ebp     ; INADDR_ANY            ; |             |
                                                ; |             |
mult:   imul    ebp, 10 ; \_                    ; |*shstrndx    |
        add     ebp, eax; >                     ; |             |
        lodsb           ; >                     ; +-------------+
        sub     al,'0'  ; >
        jns     mult    ; / ebp = atoi(argv[1])                 ;       bind stack frame
                                                                ;    +-----------------------+
endmul: inc     ebx             ; SYS_BIND (2)                  ;    |        INADDR_ANY     |
                                                                ; +->| AF_INET | htons(port) |
        bswap   ebp                                             ; |  +-----------------------+
        add     ebp, ebx        ; AF_INET (2), htons(port)      ; |  |           16          |
        push    ebp                                             ; |  +-----------------------+
                                                                ; |  |         dummy         |
        mov     ecx, esp                                        ; |  +-----------------------+
        push    16              ; addrlen                       ; |  |           16          |
        push    ecx             ; dummy value                   ; |  +-----------------------+
        push    16              ; addrlen                       ; +--|          addr         |
        push    ecx             ; addr                          ;    +-----------------------+
        push    edi             ; sock                          ;    |         sockfd        |
        mov     ecx, esp                                        ;    +-----------------------+
        mov     al, 0x66
        int     0x80            ; bind(sockfd, addr, addrlen)
                                                                ;       accept stack frame
                                                                ;    +-----------------------+
listen: ;mov    byte [esp+8],1                                  ;    |        INADDR_ANY     |
        inc     ebx                                             ; +->| AF_INET | htons(port) |
        inc     ebx             ; SYS_LISTEN (4)                ; |  +-----------------------+
        mov     al, 0x66                                        ; |+>|           16          |
        int     0x80            ; listen(sockfd, backlog)       ; || +-----------------------+
                                                                ; || |         dummy         |
        add     [esp+8], esp                                    ; || +-----------------------+
accept: mov     ecx, esp                                        ; |+-|        &addrlen       |
        inc     ebx             ; SYS_ACCEPT (5)                ; |  +-----------------------+
        mov     al, 0x66                                        ; +--|          addr         |
        int     0x80            ; accept(sockfd, addr, &addrlen);    +-----------------------+
                                                                ;    |         sockfd        |
        mov     ecx, eax        ; ecx = 4                       ;    +-----------------------+
        xchg    ebx, eax        ; ebx = acceptfd, eax = 000000xx

        lea     esi, [esp+27]   ; point to the IP part of struct sockaddr_in
        cdq

        std                     ; reverse direction for string operations
addip:  lodsb                   ; \_
        add     edx, eax        ; > edx = sum of 4 IP bytes
        loop    addip           ; /

        mov     edi, esi        ; reuse struct sockaddr_in as scratch buffer
        mov     al, 10          ; '\n'
        stosb
        xchg    ecx, eax        ; ecx = 10
        xchg    eax, edx        ; edx = 0, eax = sum

divide: div     cl              ; \_
        xchg    al, ah          ; >
        add     al,0x30         ; >
        stosb                   ; > sprintf(scratch, "%d", sum)
        inc     edx             ; >
        shr     eax, 8          ; >
        jnz     divide          ; /

write:  inc     edx             ; ndigits + 1 ('\n')
        mov     ecx, edi
        inc     ecx
        mov     al,4
        int     0x80            ; write(acceptfd, scratch, scratchlen) 
close:  mov     al, 6
        int     0x80            ; close(acceptfd)
        jmp     accept

4
Ця відповідь є недооціненою.
кіт

16

NodeJS, 146 134 127 байт

require('http').createServer((q,s)=>s.end(eval(0+q.socket.remoteAddress.replace(/^.*:|\./g,'+'))+'\n')).listen(process.argv[2])

Я нарешті дістаю, щоб опублікувати відповідь NodeJS! IPv4 лише зараз.

Приклад виконання: node script.js 1024. З іншого терміналу:

$ curl 127.0.0.1:1024
128

2
Я зараз нараховую 127 байт, хоча ви можете зменшити його до 126, замінивши '\n'рядком шаблону, що містить буквальний новий рядок.
Mwr247

Чи не виправдало б це вимоги, оскільки ви створюєте сервер HTTP, я маю на увазі, що це технічно сервер TCP, але ви не могли просто використовувати модуль TCP і зберегти собі персонажа?
МерМонти,

14

Tcl, 92

  • 1 байт збережено завдяки @DonalFellows.
proc s {c a p} {puts $c [expr [string map .\ + $a]]
close $c}
socket -server s $argv
vwait f

Досить зрозуміло:

socket -server s $argv створює розетку прослуховування на порту, вказаному в аргументах.

Кожного разу, коли надходить нове з'єднання, proc sвикликається, з параметром канал, адреса джерела та порт джерела. string mapзамінює .для +на адресу джерела, і exprарифметично оцінює результат, який потім putsназад до каналу зв'язку c.

vwait запускає цикл подій, щоб вловлювати події вхідного зв'язку.


Кредит @DonalFellows для наступного:

Ось версія, яка обробляє IPv6 (потрібен Tcl 8.6; більша частина додаткової довжини пояснюється виробленням шестигранної відповіді):

Tcl, 109

proc s {c a p} {puts $c [format %x [expr 0x[string map :\ +0x0 $a]]]
close $c}
socket -server s $argv
vwait f

1
Використання apply, здається, нічого не економить. Не можна також використовувати, tcl::mathop::+ {*}[split $a .]оскільки це трохи довше. Ви також не можете голити що-небудь із назв варіантів. Але підтримка IPv6 досить тривіальна для додання і коштує лише на кілька байтів коду більше (і тоді regsubпідхід на основі таких же рівних).
Стипендіати Дональ

ах, Tcl / Tcl-DP ... дивовижна купа інструментів. (у 90-х професор показав нам, що ми можемо написати розподілений в мережі Excel (з сіткою, включаючи оцінку формул!), що ділиться між декількома особами з (iirc) 4 (короткими) рядками для сервера та 5 для клієнтів. ..
Олів'є Дулак

proc s {c a p}вам справді потрібно все це пробіл?
кіт

12

Groovy 133 , 125 , 93 , 89

new ServerSocket(args[0]as int).accept{it<<(it.inetAddress.address as int[]).sum()+"\n"}

Можливо, лише IPv4.

Безголовки:

new ServerSocket(args[0]as int).accept{
    it << (it.inetAddress.address as int[]).sum()+"\n"
}

Тестування:

$ telnet localhost 9000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
128
Connection closed by foreign host.

1
.toInteger()as intі s.inetAddress.address*.toInteger()(s.inetAddress.address as int[]). І після цього є додатковий простір .with.
манатурка

@manatwork thx! Оновлено.
Буде Лп

9

Python 3, 170 166 147 байт

from socket import*
s=socket()
s.bind(("",int(input())))
s.listen()
while 1:
 c,a=s.accept()
 c.send(b"%d\n"%eval(a[0].replace(".","+"))),c.close()

Приймає порт stdin, лише IPv4. Працює в GNU / Linux (і, я припускаю, у більшості інших уніцій), який автоматично розширюється "" до "0.0.0.0", але не впевнений у Windows.


2
Ви можете зберегти кілька байтів. По-перше, простори в import *і , SOCK_STREAMнепотрібні. Крім того, рядок надсилання може бути записана ефективніше як c.send(b"%d\n"%eval(a[0].replace(".","+"))).
Ганнес Карппіла

2
@HannesKarppila о, дякую забув про простори, haval eval досить класний, хоча.
саммко

2
AF_INET і SOCK_STREAM - просто константи; AF_INET - це 2, а SOCK_STREAM - 1. Також, як було сказано, SOCK_STREAM не потрібен; тож ви можете скоротити це замість цього s=socket(2).
Скайлер

1
Ви не можете просто зробити socket () і тому зберегти ще один байт?
Foon

1
Ви можете зберегти 10 символів, використовуючи Python 2. Потім int(input())стає, input()і частина відправки стаєc.send(`eval(a[0].replace(".","+"))`)
Blender

9

Java, 371 368 350 344 333 310 295 282 байт

Гольф

import java.net.*;class A{public static void main(String[]n)throws Exception{ServerSocket s=new ServerSocket(Integer.decode(n[0]));for(;;){try(Socket a=s.accept()){byte[]c=a.getInetAddress().getAddress();new java.io.PrintStream(a.getOutputStream()).println(c[0]+c[1]+c[2]+c[3]);}}}}

Безумовно

import java.net.*;

class A {
    public static void main(String[] n) throws Exception {
        ServerSocket s = new ServerSocket(Integer.decode(n[0]));
        for (;;) {
            try (Socket a = s.accept()) {
                byte[] c = a.getInetAddress().getAddress();
                new java.io.PrintStream(a.getOutputStream()).println(c[0] + c[1] + c[2] + c[3]);
            }
        }
    }
}

Вихідні дані

mallard@steamroller:~$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
128
Connection closed by foreign host.

1
Вийміть int k=і замініть k на всі речі c Integer.toString(k). Щоб зберегти кілька байт.
GiantTree

1
Байт Javas досить впевнений, що набирає значення повернення для 192.168.2.1 або подібних адрес з байтом вище 127.
AlexR

1
Зміни interfaceна classповинні набрати ще кілька байт
ortis

2
Використовуйте a.getOutputStream().write((c[0] + c[1] + c[2] + c[3]+"\n").getBytes());замістьnew DataOutputStream(a.getOutputStream()).writeBytes(c[0] + c[1] + c[2] + c[3] + "\n")
ortis

3
Чи не try(Socket a=...){}коротше a.close();? Потрібна Java 7, але може набирати байтів.
Олів'є Грегоар

8

PowerShell v2 +, 303 268 257 227 байт

nal n new-object;($l=n Net.Sockets.TcpListener($args[0])).Start()
for(){($w=n IO.StreamWriter(($c=$l.AcceptTcpClient()).GetStream())).Write((([Net.IPEndPoint]$c.Client.RemoteEndPoint).Address-replace"\.",'+'|iex))
$w.Dispose()}

Збережено 35 байт завдяки Метту ... Збережено ще 11 байт шляхом згладжування New-Objectта незначних налаштувань ... Збережено ще 30 байт шляхом неявного використання localhost, а не anyIP-адреси та виправлено для облікового запису для постійного використання, як було зазначено спочатку, і я пропустив

Дійсно схожий на відповідь C # , оскільки саме .NET лежить в основі обох. Тут ми зберігаємо кілька байтів за допомогою відповіді C #, маючи можливість використовувати функцію повернення PowerShell (оточуючи нашу декларацію / призначення в паренах, а потім негайно викликаючи методи.), Але ми втрачаємо дуже багато, потребуючи сформулювати підсумок. . Той факт, що у нас є трохи коротші імена / виклики класів, насправді тому ця відповідь перемагає C #

Пояснення

Спочатку ми створюємо New-Aliasnalпсевдонімом), щоб заощадити при повторному введенні New-Objectпізніше. У решті першого рядка - налаштування слухача TCP. Ми передаємо командний рядок $args[0]як вхід для створення нового System.Net.Sockets.TcpListener, збереженого як $l. Цей об'єкт інкапсульований у парен і негайно викликається з тим, .Start()щоб він активно відкривав сокет.

Вступаючи в нескінченний forцикл, ми встановлюємо наш слухач $lблокування, з AcceptTcpClient()яким буде чекати з'єднання. Посилання на це з'єднання (після його встановлення) зберігається в $c, інкапсульоване в паренах і негайно викликається GetStream()для отримання потоку даних. Цей потік даних передається новому System.IO.StreamWriterконструктору $w, тому ми можемо ним маніпулювати. Цей конструктор сам інкапсульований у паренах і негайно викликається Write(...).

Всередині Write(...)дзвінка ми приймаємо клієнтську ручку $cта отримуємо RemoteEndPointмайно клієнта . Це єдиний спосіб (який я знайшов поки що) отримати віддалену IP-адресу. Далі нам потрібно перетворити це як [System.Net.IPEndPoint]об'єкт, щоб він був правильно відформатований, інкапсулювати це в паренах і витягнути лише .Addressвластивість. Тоді ми -replaceбуквені періоди із знаками плюс, потім передаємо його Invoke-Expression(подібному до eval), щоб отримати наше підсумок.

Після запису IO нам потрібно зателефонувати, .Dispose()щоб переконатись, що потік даних передається клієнту та закривається. Сервер TCP припиняє клієнтське з'єднання без попередження, тому залежно від клієнта, який він використовує, він може деякий час зависнути. Потім він продовжується через forцикл, не замикаючи належним чином з'єднання. Це також означає, що вона просочує пам'ять і обробляє систему як божевільна, але нас це не хвилює, правда? Можливо, вам доведеться використовувати диспетчер завдань, щоб вбити процес, коли ви закінчите роботу з сервером. : D

Також лише IPv4, оскільки підсумовуючи барфи, ефектно намагаються обробити адресу IPv6, оскільки :не є дійсним алгебраїчним оператором для iexрозбору.


2
"Протікає пам'ять і система обробляє, як божевільна" Що, ви маєте до free()них після? delete[], може бути? : P
кіт

8
@tac Так, є ціла купа .close()і .dispose()методи ми не називаючи тут , що б змусити людей на перегляд коду , щоб мати підгонку.
AdmBorkBork

О, чи не PS GC'd? Або GC робить переоцінку, а не аналіз обсягу?
кіт

@tac Так, PowerShell має збір сміття завдяки базовій системі .NET. Але, залежно від того, як ви викликаєте або використовуєте цей скрипт, ви можете зіткнутися з помилками, як ця, що протікає пам'ять у конвеєрі. Вищевказаний код також не є безпечним для потоків, і тому можна зіткнутися з проблемами GC з цим, оскільки ми не закриваємо явно сокет.
AdmBorkBork

1
Під час тестування я не міг змусити це працювати, ймовірно, через проблеми з брандмауером, які я не відчуваю як виправлення, тому я не можу бути впевнений, але ..... Я думаю, ви можете скинути "Систему" з більшості, якщо не з усіх типів у вас є, тобто: [Net.ipaddress]::Anyпрацює.
Метт

7

PHP, 161 (56?)

Це моя перша публікація тут. Я сподіваюся, що це іде правильно :)

<?php $s=socket_create_listen($argv[1]);while($c=socket_accept($s)){socket_getpeername($c,$r);socket_write($c,array_sum(explode('.',$r))."\n");socket_close($c);}

Безголовки:

<?php 
    $s = socket_create_listen($argv[1]); //Create socket
    while( $c = socket_accept($s) ) { // Loop accepting new connections
        socket_getpeername($c, $r); // Get IP address in $r
        socket_write($c, array_sum(explode('.', $r))."\n"); //Calculate sum
        socket_close($c); //Close connection and wait for next one
    }

Термінал:

$ php test.php 8080 &
$ telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
128
Connection closed by foreign host.

Це працює лише для IPV4

Редагувати : Я щойно помітив, що php підтримує базовий сервер:
я вирішив дотримуватися початкової кількості символів, якщо хтось не підтвердить, чи дозволено наступне :)

test2.php: (можливий 56-байтний розчин)

<?=array_sum(explode('.',$_SERVER['REMOTE_ADDR']))."\n";

А потім почніть службу з:

php -S localhost:8080 test2.php

Chrome як клієнт screenshot

Редагувати 2: wget як клієнт

$ wget -qO- localhost:8080
128

Я знаю, що правила кажуть: "Програма або функція читає ціле число N з аргументів або stdin", але чи нормально, якщо програма в цьому випадку є PHP сама Або використання вбудованого сервера в php вважається лазівкою?
Мікаель

Ласкаво просимо до головоломки програмування та коду для гольфу! Ваше 161-байтне рішення виглядає чудово. 56-байтне рішення, про яке ви згадали те, що було нижче test2.php? Якщо так, я думаю, вам доведеться запитати ОП, чи вважають вони такий вбудований прийнятним для цього виклику. Це не лазівка.
Алекс А.

Я б сказав, використання вбудованого TCP-сервера було б прийнятним, але в цьому випадку ми говоримо про вбудований HTTP-сервер . Таким чином, 56-байтне рішення 1) нічого не робить, якщо клієнт лише підключається і нічого не надсилає; 2) надсилає назад лише "[ср. 30 березня 10:15:02 2016] 127.0.0.1:47974 Недійсний запит (неправильний запит HTTP)" без запуску test2.php у випадку, якщо клієнт надсилає, наприклад, "foo"; 3) надсилає повний набір заголовків відповідей HTTP перед фактично необхідною відповіддю у випадку, якщо клієнт надсилає дійсний запит HTTP.
manatwork

@ Алекс А. Дякую і так, 56-байтне рішення знаходиться на тесті2.php :)
Mikael

@manatwork Ви праві, але я думав, що клієнт чітко не вказаний у цьому завданні. Так це нормально використовувати браузер або ще більш спрощене щось на зразок "wget ​​-qO- localhost: 8080" як клієнта?
Мікаель

7

Іди , 359 311

Це моя перша програма в Go - Це дозволило мені відкрити для себе одне: Це, безумовно, не гарна мова для гольфу!

(Кудо до @steve, хто займався більшою частиною гольфу!)

package main
import(n"net";t"strings";r"strconv";x"regexp";"os")
func main(){l,_:=n.Listen("tcp",":"+os.Args[1])
for{c,_:=l.Accept();var s int
for _,i:=range t.Split(x.MustCompile(":[0-9]+$").ReplaceAllLiteralString(c.RemoteAddr().String(),""),"."){
n,_:=r.Atoi(i);s=s+n};c.Write([]byte(r.Itoa(s)));c.Close()}}

2
Але це, звичайно, гарна мова для створення сервера tcp!
Numeri

1
Як не дивно, я отримую результат 360, коли я підключаюся з 192.168.0.67, а не 427.
Стів

3
Ви можете назвати рядки + пакети strconv, щоб зберегти кілька байт. наприклад "strings"стає s "strings"так, що пізніше strings.Splitстає справедливим s.Split.
Стів

1
Трохи більше байтів відголили pastebin.com/HY84sazE - зараз починаю виглядати трохи більше "в гольф"
steve

2
Якщо ви використовуєте import(."pkgname")всі функції, які будуть імпортовані в поточну область імен, ви можете скинути префікс. напр. import ."fmt"; Println("foo") Якщо ви використовуєте Sscanfз fmtпакету для розбору адреси замість регулярного вираження, це дозволить вам заощадити ще кілька байт, що дасть вам хороший бонус Fprintlnза повернення загальної суми замість імпорту strconv.
Крістофер Салл-Сторгард

7

Лист звичайний, 110 байт

(use-package'usocket)(lambda(p)(socket-server"localhost"p(lambda(u)(format u"~D~%"(reduce'+ *remote-host*)))))

Деталі

(use-package 'usocket)

(lambda (port)

  ;; create server with event-loop
  (socket-server "localhost"
                 port

                 ;; tcp-handler
                 (lambda (stream)
                   ;; format to stream to client
                   (format stream
                           "~D~%"
                           ;; add all elements of the host,
                           ;; a vector of 4 integers
                           (reduce #'+ *remote-host*))

                   ;; client connection is closed automatically
                   ;; when exiting this function                     
                 )))

2
Так, для звичайного літпу!
кіт

6

q, 88 байт

system raze"p ",1_.z.x;.z.pg:{(string sum"i"$0x0 vs .z.a),"\n"};.z.ph:{.h.hy[`;.z.pg[]]}
  • system raze"p ",1_.z.x: Бере другий аргумент командного рядка (перший "-"- для того, qщоб сказати не інтерпретувати Nяк сценарій / файл) і відкриває з ним порт ( "p ").
    • Примітка: Виклик q -p Nвстановлює порт як Nавтоматично, але оскільки питання, схоже, підказує, що це Nповинен бути аргументом для програми, а не для самого виконуваного файлу, я пройшов довший шлях.
  • Всередині .z.pgфункції, яка обробляє вхідні запити, .z.aзберігає IP-адресу як 32-бітове ціле число.
    • "i"$0x0 vsрозбиває його на цілі "складові" і sumробить підсумок.
    • Нарешті, stringчисловий результат і додайте "\n"до нього, щоб повернутися до клієнта.
  • .z.ph - це ще одна функція для HTTP GET-запитів, з додатковою обробкою для перетворення рядкового виводу у дійсну відповідь HTTP.

Демонстраційний сервер:

c:\q\w32>q - 1234
KDB+ 3.3 2015.11.03 Copyright (C) 1993-2015 Kx Systems
w32/ 4()core ... NONEXPIRE

Welcome to kdb+ 32bit edition
q)system raze"p ",1_.z.x;.z.pg:{(string sum"i"$0x0 vs .z.a),"\n"};.z.ph:{.h.hy[`;.z.pg[]]}
q)

Демонстрація - клієнт (від іншого q сеансу, що триває 127.0.0.1):

q)(hopen `::1234)""
"128\n"

Демо - клієнт (від curl):

$ curl localhost:1234
128

$

6

LiveScript, 107 105 байт

(require \http)createServer(->&1.end((.reduce (+))<|it.connection.remoteAddress/\.))listen process.argv.0

Нічого особливо не додати, це просто основні речі NodeJS. Точки стилю для &1(другий аргумент), <|(F # трубопровід, схожий на $Haskell) та biop: (+)у LS - це як операторські розділи в Haskell: curried бінарна функція (що додає її операнди). Також трохи брудно: /якщо йому дано буквальний рядок праворуч, буде зроблено розділення.


5

Perl, 141 132 + 1 = 133 байт

Гольф

$s=new IO::Socket::INET LocalPort=><>,Listen=>5,Reuse=>1;{$c=$s->accept;$_=$c->peerhost;y/./+/;$c->send(eval.$/);shutdown $c,1;redo}

Безумовно

# listen on tcp port obtained from stdin
$s=new IO::Socket::INET(LocalPort=> <>,
                        Listen   => 5,
                        Reuse    => 1);

{
    # accept connection
    $c=$s->accept();

    # get the ip address
    $_=$c->peerhost();

    # replace dots with plus
    y/./+/;

    # send the evaluated version back, with a newline
    $c->send(eval . $/);

    # close
    shutdown($c,1);

    redo;
}

Приклад

$ echo 7777|perl -MIO::Socket::INET -e'$s=new IO::Socket::INET LocalPort=><>,Listen=>5,Reuse=>1;{$c=$s->accept;$_=$c->peerhost;y/./+/;$c->send(eval.$/);shutdown $c,1;redo}'

$ telnet 127.0.0.1 7777
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
128
Connection closed by foreign host.
$

Ви впевнені, що це правильно? Я отримую суму, надруковану в терміналі сервера, а не в клієнтській. У будь-якому випадку ви можете видалити всі дужки та змінити s/\./+/gy/./+/.
манатурка

Ах, непрочитано ... перегляньте відповідним чином і включіть ваші добрі пропозиції / пропозиції.
Стів

1
while(1){…}{…;redo}згідно user130144 великий «и наконечник . І крім ->send()виклику, всі інші дужки є непотрібними.
манатура

4

Python 2, 180 байт

from SocketServer import*
TCPServer(('',input()),type('',(BaseRequestHandler,set),{'handle':lambda s:s.request.send(`eval(s.client_address[0].replace('.','+'))`)})).serve_forever()

Займає порт над stdin.


4

NodeJS (ES6), 129 118 107 байт

require('net').createServer(c=>c.end(eval(c.remoteAddress.replace(/\./g,'+'))+`
`)).listen(process.argv[2])

Працює для IPv4. Виконати якnode server.js <port>


Насправді не працює, якщо сервер використовує IPv6 (як, наприклад, моя робить автоматично), оскільки це c.remoteAddressбуло б ::ffff:127.0.0.1. (Я тестував на Node v5.9.1).
Frxstrem

Крім того, у вас немає останнього нового рядка, який повинен збільшити бал на 2 байти.
Frxstrem

@Frxstrem Whoops, забув цей новий рядок. Додає лише 1 байт, хоча завдяки рядкам шаблону. Щодо сімейства IP: .listen()раніше використовується за замовчуванням для IPv4, але здається, що помилка чи дизайн змінили це. Подання все ще буде функціонувати належним чином на новіших версіях вузла, коли IPv6 відключений на хост-машині.
M24r

4

Ідіть, 211 байт

package main
import(."fmt"
."net"
"os")
func main(){s,_:=Listen("tcp4",":"+os.Args[1])
for{c,_:=s.Accept()
var a,b,d,e int
Sscanf(Sprint(c.RemoteAddr()),"%d.%d.%d.%d",&a,&b,&d,&e)
Fprintln(c,a+b+d+e)
c.Close()}}

Можливо, може бути ще більше гольфу, я не цілком задоволений тим, як я маю розібрати IP-адресу, наприклад, це виглядає як жахливий злом.

Слухає IPv4 на порту, поданий як аргумент.


4

PowerShell, 208 206 192 152 байт

($t=[net.sockets.tcplistener]$args[0]).start();for(){($z=$t.acceptsocket()).sen‌d([char[]]"$($z.remoteendpoint.address-replace"\.","+"|iex)");$z.close()}

інформація про версію:

Name                           Value
----                           -----
PSVersion                      4.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.34209
BuildVersion                   6.3.9600.17400
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion      2.2

Дякую TimmyD, що врятував мені 14 байт!

Величезне спасибі TessellatingHeckler за те, що врятував мені 40 байт


@TimmyD ах ой, ой, я пропустив те, що було потрібно ... виправлено зараз
Nacht

Один із способів, яким програма може дозволити приймати дані, - це від stdin. Я думаю, що в цьому конкретному питанні це не вказано як дозволене, але це загальна річ з кодом-гольф, яку, на мою думку, слід розраховувати на PowerShell. Він, на жаль, відрізняється від bash тим, що він не чекає введення на stdin, якщо його не було надано.
Нахт

досить справедливо. виправлено знову
Нахт

Добре, тепер для деяких гольфів - спробуйте наступне на 192 -($t=new-object net.sockets.tcplistener($args[0])).start();for(){($z=$t.acceptsocket()).send(($x=[byte[]][char[]](""+($z.remoteendpoint.address-replace"\.","+"|iex))+32),$x.count,0);$z.close()}
AdmBorkBork

1
Я думаю, що ви можете збити це до 152 - киньте новий об’єкт і передайте безпосередньо, пропустіть конвертацію масиву байтів і зробіть рядок по-різному, не зберігайте $ x взагалі і не скидайте решта параметрів для send (), і це стає ($t=[net.sockets.tcplistener]$args[0]).start();for(){($z=$t.acceptsocket()).send([char[]]"$($z.remoteendpoint.address-replace"\.","+"|iex)");$z.close()}- що я швидко протестував лише за допомогою з'єднання з мережею, але, здається, працює те саме - підключення з localhost все одно.
TessellatingHeckler

4

8086 машинного коду (16-бітний DOS), 163 156 148 148 142 байт

00000000  31 c0 bb 0a 00 31 c9 be  81 00 bf 80 00 8a 0d 01  |1....1..........|
00000010  cf 46 8a 0c 80 e9 30 f7  e3 00 c8 39 fe 72 f2 89  |.F....0....9.r..|
00000020  c3 89 c1 b8 01 10 ba ff  ff 31 f6 31 ff cd 61 53  |.........1.1..aS|
00000030  b8 00 12 bf 80 00 b9 01  00 ba ff ff cd 61 b8 00  |.............a..|
00000040  14 cd 61 31 c0 bb 0a 00  83 c7 06 8d 4d 04 26 02  |..a1........M.&.|
00000050  05 80 d4 00 47 39 cf 72  f5 bf 84 00 b9 80 00 bb  |....G9.r........|
00000060  0a 00 4f 31 d2 f7 f3 80  c2 30 88 15 39 cf 77 f2  |..O1.....0..9.w.|
00000070  1e 07 b8 0e 13 5b bf 80  00 b9 04 00 ba ff ff cd  |.....[..........|
00000080  61 b8 00 11 ba 01 00 cd  61 b8 00 4c cd 21        |a.......a..L.!|
0000008e

Еквівалентний код складання:

org 0x100
tcp equ 0x61    ; NTCPDRV interrupt

    xor ax,ax
    mov bx,10
    xor cx,cx
    mov si,0x81     ; [ds:81]-[ds:FF] = command line args
    mov di,0x80     ; [ds:80] = strlen(args)
    mov cl,[di]
    add di,cx

@@: inc si
    mov cl,[si]     ; get character
    sub cl,'0'      ; convert char to int
    mul bx          ; ax *= 10
    add al,cl
    cmp si,di
    jb @b
    ; now ax = port number

    mov bx,ax       ; source port (leaving this 0 doesn't work?)
    mov cx,ax       ; dest port
    mov ax,0x1001   ; open TCP socket for listening
    mov dx,-1       ; infinite timeout
    xor si,si       ; any dest IP
    xor di,di
    int tcp
    ; ^ I think this call should block until a connection is established, but apparently it doesn't.

    push bx         ; bx = socket handle, save it for later

    mov ax,0x1200   ; read from socket
    mov di,0x80     ; es:di = buffer (just reuse argument area to save space)
    mov cx,1        ; one byte
    mov dx,-1
    int tcp         ; this will block until a client connects and sends one byte

    mov ax,0x1400   ; get TCP session status, bx=handle
    int tcp
    ; now es:di points to a struct containing the source/dest IP addresses and ports
    ; the docs say it's two dwords for each IP address, then two bytes for "ip_prot" and "active" (whatever that means)
    ; ...but actually each IP address is followed by the port number (one word)

    xor ax,ax
    mov bx,10
    add di,6        ; [es:di+6] = client IP
    lea cx,[di+4]
@@: add al,[es:di]  ; add all bytes together
    adc ah,0
    inc di
    cmp di,cx
    jb @b
    ; now ax contains the IP address sum

    mov di,0x84     ; recycle arguments area again
    mov cx,0x80
    mov bx,10
@@: dec di
    xor dx,dx
    div bx          ; dl = ax mod 10
    add dl,'0'      ; convert int to char
    mov [di],dl
    cmp di,cx
    ja @b
    ; now [ds:80]-[ds:83] contains an ascii representation of the IP address sum

    push ds
    pop es
    mov ax,0x130e   ; send data with newline, wait for ack
    pop bx          ; socket handle
    mov di,0x80     ; es:di = data
    mov cx,4        ; sizeof data
    mov dx,-1
    int tcp

    mov ax,0x1100   ; close TCP socket
    mov dx,1
    int tcp

    mov ax,0x4c00
    int 0x21

Це передбачає ntcpdrv, що завантажується в INT 0x61(і будь-який відповідний драйвер пакету на 0x60). Компілювати зfasm tcpserv.asm .

Однак у нього є деякі проблеми:

  • Він не перевіряє, чи аргумент є дійсним номером порту, чи це взагалі число.
  • Клієнт повинен надіслати щонайменше один байт, оскільки я не можу знайти іншого способу сказати, чи підключився клієнт.
  • Він працює лише один раз і зависає з другої спроби. Працює знову після перезавантаження.
  • Повернене значення залишене нулями.
  • Це мій перший запис про гольф з кодом, а також моя найперша програма з посиланням 8086. Я впевнений, що є шляхи покращення цього.

1
Ви можете просто опублікувати шестнадцятковий компільований вихід на 148 байт
кіт

Це дозволено? Це зробило б цей запис трохи більш конкурентоспроможним ...
user5434231

1
Добре, я змінив запис до машинного коду. Також поголив ще кілька байтів, використовуючи xor r,rзамість цього mov r,0.
користувач5434231

1
Я написав це на машині дос, де є нові рядки CR LF, тому я просто пішов з цим. Так чи інакше безглуздо зараз рахувати розмір ASM, можливо, трохи очистити його та додати коментарі.
користувач5434231

1
Це повинно відбутися і тут, і це спрацює; int 0x61повертає випадковий локальний порт у ax. Але це також змінює IP прослуховування на якийсь номер сміття ( 4.2.0.0iirc)
user5434231

3

Haskell, 216 байт

Використання пакету "мережа-простий" ( cabal install network-simple). Для роботи потрібно кілька розширень мови ( -XOverloadedStrings -XNoMonomorphismRestriction).

import Network.Simple.TCP(serve)
import Network.Socket
import Data.Bits
main=getLine>>= \n->serve"*"n p
p(s,(SockAddrInet _ h))=()<$(send s$(show$sum$w h 24)++"\n")
m=255
w h 0=[h.&.m]
w h n=h`shiftR`n.&.m:(w h$n-8)

Існує пара можливих спрощень, включаючи зміну wфункції повернення суми безпосередньо, а не списку, та використання функції, а не програми, щоб номер порту можна вказати як аргумент. Я не думаю, що це значно зменшить розмір. 20 байт, можливо?


Приємно! Досить впевнений, що ви все ще можете поголити кілька байтів, перейменувавши їх wна #так, це w h nстає h#nдля економії 2 байт за використання.
Actorclavilis

3

Свинка, 114 115 байт

Гольф:

R P F{S J=0,I="|TCP|1" O I:(:P) U I R K F K=1:1:4{S J=J+$P(##class(%SYSTEM.TCPDevice).PeerAddr(),".",K)} W J,! C I}

Безголовки:

R P             ; Read Port # from STDIN ;
  F{            ; Loop over everything;
  S J=0,        ; Initial IP segment total
  I="|TCP|1"    ; TCP device
  O I:(:P)      ; Open the TCP device, port from input {and sticking a tongue out! :-) }
  U I           ; Use the TCP device
  R K           ; Read from STDIN (anything)
  F K=1:1:4{    ; Iterate 1->4 in variable K
    S J=J+      ; Accumulate the following segments of the IP in var. J
    $P(##class(%SYSTEM.TCPDevice).PeerAddr(),".",K) ; Grab each piece of IPv4.
            }   ; close the loop.
  W J,!         ; Write the total w/newline out the TCP port 
  C I           ; close the TCP port to send.
}               ; end final loop

Це версія Mumps InterSystems Caché - якщо там є версія, яка може отримати TCP-адресу коротше ##class(%SYSTEM.TCPDevice).PeerAddr() (оскільки це майже 1/3 всієї програми) це може мати більше шансів проти деяких інших мов, розміщених уже ... ;-)

Редагувати: Завдяки @TimmyD - я пропустив читання порту зі STDIN або аргументів, замість того, щоб бути жорстко кодованим. Відредаговано; це додало 1 байт до програми.


@TimmyD - Ах, ти маєш рацію. Пропустив це при читанні вимог. Відредагує постхасте.
zmerch

3

C, 535 байт

Ну, хтось повинен був це зробити.

Я додав один розрив рядка, щоб розміщений код насправді мав 536 символів.

#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
int main(int c,char**v){int f,l;char b[99];struct sockaddr_in d,e;f=socket(AF_INET,SOCK_STREAM,0);bzero(&d,sizeof(d));d.sin_family=AF_INET;d.sin_addr.s_addr=INADDR_ANY;d.sin_port=htons(atoi(v[1]));bind(f,&d, sizeof(d));listen(f,5);l=sizeof(e);
f=accept(f,&e,&l);bzero(b,99);int p,q,r,s;char g[INET_ADDRSTRLEN];inet_ntop(AF_INET,&(e.sin_addr),g,INET_ADDRSTRLEN);sscanf(g,"%d.%d.%d.%d",&p,&q,&r,&s);sprintf(b,"%d\n",p+q+r+s);write(f,b,strlen(b));return 0;}

компілювати с gcc [file_name] -o server

бігати з ./server [port]

з'єднатися з telnet localhost [port]


3
Гарна відповідь! Як згадувалося раніше , ви можете зберегти кілька байт, використовуючи фактичні значення для деяких констант, таких як AF_INET і SOCK_STREAM.
Ганнес Карппіла

2

Java, 210 байт

Гольф:

p->{java.net.ServerSocket x=new java.net.ServerSocket(p);for(;;){try(java.net.Socket s=x.accept()){byte[]b=s.getInetAddress().getAddress();s.getOutputStream().write((0+b[0]+b[1]+b[2]+b[3]+"\n").getBytes());}}};

Розширено:

@FunctionalInterface interface Consumer { // Define an interface that allows a function that throws an exception.
  void accept(int port) throws Exception;
}

Consumer consumer = (port) -> {
  java.net.ServerSocket serverSocket = new java.net.ServerSocket(port);
    for (;;) {
      try (java.net.Socket socket = serverSocket.accept()) {
        byte[] bytes = socket.getInetAddress().getAddress();
        socket.getOutputStream().write((0 + b[0] + b[1] + b[2] + b[3] + "\n").getBytes());
      }
    }
}

Це зібрання всіх порад, які я дав в інших відповідях Java, плюс написання як функція замість повноцінної програми, яка набирає приблизно 70 байт порівняно з програмою.


2

Haskell, 326 байт

import Data.Bits
import Network.Socket
import System.IO
f n=withSocketsDo$do
 s<-socket AF_INET Stream defaultProtocol
 bind s$SockAddrInet n iNADDR_ANY
 listen s 1
 g s
g s=do
 (z,SockAddrInet _ a)<-accept s
 h<-socketToHandle z WriteMode
 hPutStrLn h$show$b a
 hClose h
 g s
b 0=0
b x=x.&.0xFF+b(x`shiftR`8)

На жаль, мені довелося використовувати, Network.Socketщоб отримати доступ до віддаленої IP-адреси як ціле число, а не рядок. Було б врятовано десятки символів, якби я міг просто це зробити s <- listenOn (PortNumber n), а не явно телефонувати socket, bindі listenокремо. Але, на жаль,Network.accept дає мені приймаючу рядок , а НЕ IP - адреса ціле , так що мені довелося вдатися доNetwork.Socket.accept і друзям.

Функція f приймає номер аргументу як аргумент і створює серверний сокет ( s), який прослуховує цей порт. Потім він викликає функцію gза допомогою серверного сокета. gпетлі назавжди, приймаючи з'єднання. Функція bприймає фактичну адресу IPv4 і обчислює суму її цифр.

Я впевнений, що хтось десь може зробити це краще, ніж я. Мені хотілося показати, наскільки проклятий простий гніздовий матеріал у Haskell ... але потім нещасно не вдалося, тому що мені потрібен доступ до IP-адреси, яку, як правило, не легко отримати.


Пакет "мережа-простий" забезпечує набагато приємніший інтерфейс, який передає SockAddr функції, яку ви йому надаєте, що полегшує справи. Дивіться моє рішення, яке я збираюся опублікувати ...
Жуль

Очевидне декілька спрощень: (1) Я вважаю, що withSocketsDoце потрібно лише в Windows, тому якщо він працює в Linux, його можна ігнорувати; (2) 0xFF - символ довше 255; (3) перетворення розетки на ручку та використання звичайного вводу-виводу набагато довше, ніж використанняNetwork.Socket.send . Так, sendзастаріле, але причина не стосується цього сценарію (він стосується лише текстових або бінарних даних, що не належать до ASCII), тому його представляється розумним використовувати.
Жуль

Network.accept gives me a host string, not an IP address integerХіба ви не можете просто розділити рядок IP на ".", mapфункції в Haskell рядок-к-номеру над розділеної рядки і підвести підсумки?
кіт

2

Луа, 169 162 160 153 151 148 138 129 байт

Гольф-версія

m=require"socket".bind(0,...)::l::c=m:accept()f=0 for n in c:getpeername():gmatch"%d+"do f=f+n end c:send(f.."\n")c:close()goto l

Він вимагає встановлення Luasocket та перекладача, який підтримує мітки. Я перевірив його з Luajit, і я також можу підтвердити, що код не працює з Lua 5.1.

Безгольова версія

m=require"socket".bind(0,...)
::l::
c=m:accept()

f=0
for n in c:getpeername():gmatch"%d+" do
    f=f+n
end
c:send(f.."\n")

c:close()
goto l

Редагувати 1:

Змінено i=({c:getpeername()})[1] на простоi=c:getpeername()

Редагувати 2:

Вилучені дужки із заяви оператора.

Редагувати 3:

Зняв дужки навколо варагу, трохи зменшив кількість байтів.

Редагувати 4:

Видалено круглі дужки навколо "% d +", коротше на 2 байти.

Редагувати 5:

Видалено непотрібну змінну i.

Редагувати 6:

Змінено ip з "127.0.0.1" на 0. (Завдяки xyzzy на #lua)

Редагувати 7:

Вилучено виклик функції toumber, оскільки рядки автоматично передаються на номери (Спасибі Trebuchette за пропозицію, я цього не знав)


1
Лише для Lua 5.2 та новіших міток підтримки, якщо вам цікаво
Trebuchette

1
Також Lua автоматично передає рядки на номери +оператору, тож ви можете виводити їх tonumber.
Trebuchette

2

Haskell, 185 (+ 19 = 204)? байт

import Network.Simple.TCP(serve)
import Network.Socket
import Data.List.Split
main=getLine>>=flip(serve"*4")(\(a,b)->()<$(send a$(++"\n")$show$sum.map read.take 4.sepByOneOf":."$show b)

Приймає номер порту як один рядок на stdin; вимагає network-simpleвід Кабала.

Як зазвичай у відповідях Haskell, які не обмежують себе чистими функціями, importsзабирають занадто багато байтів. Новий рядок також коштує 9 байт ...

Дещо схожа на відповідь @ Jules, але я використовую маніпуляції з рядками замість байтових операцій. Я вкрав і -XOverloadedStringsрозширення, яке, мабуть, вартує ще 19 байт.


2

C, 243 188 байт (або, можливо, 217 162 байт)

V2: див. Пояснення нижче.

188 байт:

s;main(g,v)char**v;{short S[8]={2,htons(atoi(v[1]))};char C[g=16];bind(s=socket(2,1,0),&S,g);for(listen(s,8);g=fdopen(accept(s,&C,&g),"w");fclose(g))fprintf(g,"%d\n",C[4]+C[5]+C[6]+C[7]);}

Трохи точні 162 байти:

s;main(g){short S[8]={2,g};char C[g=16];bind(s=socket(2,1,0),&S,g);for(listen(s,8);g=fdopen(accept(s,&C,&g),"w");fclose(g))fprintf(g,"%d\n",C[4]+C[5]+C[6]+C[7]);}

Можливо, завтра вранці можливо більше гольфу. Я остороньте цю публікацію після цих оновлень.


V1:

Цей був дійсно досить утішний гольф.

#include<netdb.h>
s,c,q;main(g,v)char**v;{struct sockaddr_in S={2,htons(atoi(v[1]))},C;bind(s=socket(2,1,0),&S,g=16);for(listen(s,8);c=accept(s,&C,&g);q=fclose(g)){for(g=4;g;q+=C.sin_addr.s_addr>>8*--g&255);fprintf(g=fdopen(c,"w"),"%d\n",q);}}

Він працює для IPv4. Переважно це просто реалізація. Три основні компоненти є

Створення розетки:

struct sockaddr_in S = {2, htons (atoi (v [1]))}, C; bind (s = socket (2,1,0), & S, g = 16);

Ми використовуємо різні явні форми констант AF_INET тощо і використовуємо той факт, що коли структура ініціалізується в C таким чином, неозначені елементи встановлюються в нуль.

Слухайте клієнтів, приймайте їх та закривайте їхні зв’язки:

for (прослухати (s, 8); c = прийняти (s, & C, & g); q = fclose (g))

Нарешті, щоб надіслати кожному клієнту дані:

для (g = 4; g; q + = C.sin_addr.s_addr >> 8 * - g & 255); fprintf (g = fdopen (c, "w"), "% d \ n", q);

IP зберігається у C.sin_addr.s_addrвигляді 32-бітного цілого числа, де кожен октет представлений одним із чотирьох байтів. Ми підсумовуємо ці байти з циклом for, а потім друкуємо їх у потік за допомогою fprintf.

У мене коротше 217 байт рішення, але я не зовсім впевнений, що він не порушує стандартні лазівки, оскільки вимагає, щоб порт був заданий в одиничному порядку в мережевому байті як аргументи командного рядка. Тобто для запуску сервера на порту 12345 потрібно було б зателефонувати

$ ./tcp 1 1 1 1 ... 1 1 1

де загальна кількість 1s - 14640. Якщо не менше - це трохи ... громіздко. Але ось це все одно:

#include<netdb.h>
s,c,q;main(g){struct sockaddr_in S={2,g},C;bind(s=socket(2,1,0),&S,g=16);for(listen(s,8);c=accept(s,&C,&g);q=fclose(g)){for(g=4;g;q+=C.sin_addr.s_addr>>8*--g&255);fprintf(g=fdopen(c,"w"),"%d\n",q);}}

2

Ракетка, 265 байт

#lang racket(define l(tcp-listen(string->number(read-line))))(let e()(define-values(i o)(tcp-accept l))(thread(λ()(define-values(a b)(tcp-addresses o))(write(~a(foldl + 0(map string->number(string-split a".")))o))(newline o)(close-output-port o)))(e)))

Безголовки:

#lang racket
(define listener (tcp-listen (string->number (read-line))))
(define (mk-server)
  (let echo-server ()
    (define-values (in out) (tcp-accept listener))
    (thread
     (λ()
       (define-values (a b) (tcp-addresses out))
       (write (number->string (foldl + 0(map string->number(string-split a "."))) out))
       (write "\n" out)
       (close-output-port out)))
    (echo-server)))

2

Фактор, 155 146 131 206 190 байт

Ну, я просто багато дізнався про програмування сокетів низького рівня. Я не думаю, що я ніколи не хочу це робити знову, тому що мій Чет болить голова.

[ utf8 <threaded-server> readln 10 base> >>insecure [ remote-address get host>> "." split [ 10 base> ] map sum 10 >base print flush ] >>handler [ start-server ] in-thread start-server drop ]

О так, нитка, і не повертається, правда.


Можна використовувати 10 base>замість string>number?
федерація.

@fedes. Нічого собі, я ніколи не знав, що це існує. Я думаю, що це дозволить мені скоротити багато моїх відповідей на "Фактор"!
кіт

І 10 >baseдля числа> рядок, також.
федерація.

1
@fedes. Вони заслуговують на відповідь тут : D
кіт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.