Prosty serwer TCP


104

Napisz program lub funkcję, która nasłuchuje przychodzącego ruchu TCP na porcie N. Oferuje prostą usługę: oblicza sumę pól adresu IP połączenia przychodzącego i zwraca.

Program lub funkcja odczytuje liczbę całkowitą N z argumentów lub standardowego wejścia. Nasłuchuje przychodzących połączeń TCP na porcie N. Gdy ktoś łączy się z tym portem, program oblicza sumę pól adresu IP i odsyła go z powrotem do klienta z nową linią i zamyka połączenie.

  • Numer portu N jest prawidłowym portem, a 2 10 <N <2 15
  • Doczepiany nowej linii może być \nalbo\r\n
  • Możesz użyć IPv4 lub IPv6. Ponieważ adresy IPv6 są zapisywane w formie szesnastkowej, należy również podać wynik w tym samym formacie, na przykład 2001:0db8:0000:0042:0000:8a2e:0370:7334 => 12ecd.

To jest . Obowiązują standardowe zasady i luki.

Przykład

Uruchamiasz swój serwer za pomocą ./server 1234. Serwer jest teraz uruchomiony i czeka na połączenia na porcie 1234. Następnie klient z 127.0.0.1łączy się z serwerem. Serwer wykonuje proste obliczenia: 127+0+0+1 => 128i wysyła wynik do klienta (ze spływu nowej linii) 128\n. Następnie serwer zamyka połączenie i czeka na następnego klienta.

Tabela liderów

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
Czy można używać inetd / xinetd lub podobnego?
Cyfrowa trauma

91
Lubię to, ponieważ jest to wyzwanie w golfa, w którym mało prawdopodobne jest, aby języki gry w golfa były bardzo dobre.
isaacg

9
Niesamowite jest nie tylko to, że serwer TCP jest najwyraźniej bardzo łatwym programem do pisania, ale jestem całkowicie przekonany, że gra w golfa dla zabawy. Wrócę do walki z FizzBuzzem jak imbecyl.
MonkeyZeus

17
@isaacg Jest tylko czas, aby ktoś znalazł wbudowany serwer TCP w Mathematica
Downgoat

3
@MonkeyZeus Szczerze mówiąc, nie zobaczysz tutaj żadnego dobrego serwera TCP. Stworzenie niezawodnego, skalowalnego serwera TCP, który dobrze obsługuje wszystkie zawiłości protokołu TCP (i protokołu aplikacji) jest nieco trudniejsze: D Chociaż z pewnością pomaga to w niezwykle prostym protokole - nie musisz nawet czytać strumienia, coś które widziałem
włamane

Odpowiedzi:


57

Bash + netcat + ss +…, 65 60 znaków

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

Nie było to poważne rozwiązanie, byłem tylko ciekawy tej możliwości.

Dzięki:

  • ninjalj za sugerowanie awkopartego na filtrowaniu (-5 znaków)

Przykładowy przebieg:

(Terminal 1)

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

(zacisk 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.

Na Ubuntu możesz pobrać ncz netcat-traditional (nie, netcat-openbsd nie jest dobry) i ssz iproute2 .


22
Dlaczego mówisz, że to nie jest poważne rozwiązanie? Tak długo, jak działa zgodnie z oczekiwaniami, nie widzę powodu, dla którego nie powinien być uważany za poważny. Jest to również najkrótszy o dość znaczący margines w tej chwili.
Alex A.

Największe obawy pojawiły się podczas dyskusji z @JesseSielaff, kiedy dowiedziałem się, że w systemach ze skonfigurowanym IPv6 informacje związane z gniazdami mogą być sformatowane inaczej. Nie mam takiego systemu, aby go przetestować. Dla którego myślę, czy bardziej poprawne byłoby przekształcenie go w CW.
manatwork

3
Rozumiem specyfikację, że musisz obsługiwać IPv4 lub IPv6, a nie oba. Tak długo, jak działa dla IPv4, nieobsługiwanie IPv6 nie powinno mieć znaczenia, tak sądzę.
Alex A.

1
@AlexA. Przynajmniej myślę, że moje pytanie tak mówi. Czy powinienem to wyjaśnić?
Hannes Karppila

@HannesKarppila, twoje pytanie jest jasne. Możliwym problemem jest to, że moje rozwiązanie może wymagać skonfigurowania systemu operacyjnego w określony sposób, aby można go było uruchomić. Martwię się, ponieważ może się nie powieść, jeśli skonfigurowany jest protokół IPv6, niezależnie od tego, czy go obsłużę, czy nie. Ktoś, kto ma skonfigurowany IPv6, może to powiedzieć na pewno…
manatwork

23

C #, 284 283 282 278 274 254 bajtów

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]);}}}

Klasyczny przykład podstawowego serwera C # TCP. Testowanie:

Terminal 1:

$ ./Q76379.exe 1029

Terminal 2:

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

Firefox:


7
Możesz zapisać 1 bajt, używając int Mainzamiast void Main. Ponieważ program nigdy nie zwraca kompilatora, nie wymaga returninstrukcji.
raznagul

I nie, to nie przecieka. To tak naprawdę dość deterministyczne w kwestii uwalniania zasobów. Ponadto argument do Startjest opcjonalny, zapisując inny znak.
Luaan

@Luaan Tak, to zostało po debugowaniu.
LegionMammal978

Możesz także użyć usingna TcpClient, który pozwoli ci uratować trzy kolejne postacie (użyj {}z for), i robienie tego samego z tym StreamWriterpowinno uratować jeszcze jedną.
Luaan

@Luaan muszę wyraźnie aby to działało poprawnie. FlushStreamWriter
LegionMammal978

22

Linux ELF / x86, 146 bajtów

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

Zawiera 52-bajtowy nagłówek ELF, 32-bajtowy nagłówek programu, 111 bajtów kodu programu + 3 bajty kodu do przeskakiwania wewnątrz nagłówków.

Informacje na temat sposobu tworzenia plików wykonywalnych ELF malutkie można znaleźć na Breadbox „s « wicher Kurs tworzenia Really teensy ELF wykonywalne dla systemu Linux » .

Linux / i386 korzysta z socketcall(2)multipleksowego wywołania systemowego, które przyjmuje ebxokreślone wywołanie gniazda ( SYS_*makra z /usr/include/linux/net.h) oraz ecxwskaźnik do obszaru argumentów oryginalnego wywołania biblioteki.

Niektóre rzeczy zrobione, aby mały rozmiar pliku wykonywalnego:

  • Zakłada, że ​​rejestry są zerowane przy wejściu, co robi Linux, ale nie jest wymagane przez standard ELF (jedynym warunkiem jest to, że przy wejściu EDXwskazuje na funkcję finalizacji (przydatną dla plików wykonywalnych ładowanych przez dynamiczny linker) lub ma wartość NULL).
  • Zakłada się, że przy uruchomieniu (zwykle przez powłokę) jedynymi otwartymi deskryptorami plików są 0, 1 i 2. Oznacza to, że nasłuchującym gniazdem będzie fd 3, a zaakceptowanym gniazdem będzie fd 4.
  • Zakłada się, że istnieją dokładnie 2 argumenty (w tym argv[0]).
  • Ta sama przestrzeń stos jest wykorzystywany do połączeń do bind(2), listen(2)i accept(2).
  • Aby pominąć pola phentsizei phnum, poprzedzany jest bajt, który zamienia się w CMPoperację, która natychmiast przyjmuje pola phentsizei phnum(sztuczka bezwstydnie skradziona z rozwiązania breadbox do 123 w anarchicznym golfie ).
  • Operacje na łańcuchach x86 LODS(ładowanie do akumulatora i indeks źródła inkrementacji / dekrementacji) oraz STOS(zapisywanie z akumulatora i indeksu docelowego inkrementacji / dekrementacji) są dobre dla krótkiego kodu.
  • XCHG EAX, regjest 1-bajtowy, w porównaniu do MOV EAX, reg, który zajmuje 2 bajty.
  • CDQ/CLTD(znak-przedłużenie EAXdo EDX:EAX) może być używany jako 1-bajtowy sposób zerowania EDXrejestru.
  • BSWAPjest przydatny do wdrożenia htons().

Źródło 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
Ta odpowiedź jest niedoceniana.
kot

16

NodeJS, 146 134 127 bajtów

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

W końcu mogę opublikować odpowiedź NodeJS! Tylko teraz IPv4.

Wykonanie próbki: node script.js 1024. Z innego terminala:

$ curl 127.0.0.1:1024
128

2
Zliczam teraz 127 bajtów, chociaż można go zmniejszyć do 126, zamieniając się '\n'ciągiem szablonu zawierającym dosłowny znak nowej linii.
Mwr247,

Czy nie spełniłoby to wymagań, ponieważ tworzenie serwera HTTP jest technicznie serwerem TCP, ale czy nie mógłbyś po prostu użyć modułu TCP i zapisać siebie?
MayorMonty

14

Tcl, 92

  • 1 bajt zapisany dzięki @DonalFellows.
proc s {c a p} {puts $c [expr [string map .\ + $a]]
close $c}
socket -server s $argv
vwait f

Dość oczywiste:

socket -server s $argv tworzy gniazdo nasłuchujące na porcie określonym w argumentach.

Za każdym razem, gdy pojawia się nowe połączenie, proc sjest ono wywoływane z parametrem kanał, adres źródłowy i port źródłowy. string mapzastępuje .na +adres źródłowy i exprarytmetycznie ocenia się wynik, który jest następnie putsz powrotem do kanału połączeniowego c.

vwait uruchamia pętlę zdarzeń, aby przechwycić przychodzące zdarzenia połączenia.


Kredyt dla @DonalFellows za:

Oto wersja, która obsługuje IPv6 (wymaga Tcl 8.6; większość dodatkowej długości wynika z generowania odpowiedzi szesnastkowej):

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
Używanie applywydaje się niczego nie oszczędzać. Nie możesz też użyć, tcl::mathop::+ {*}[split $a .]ponieważ jest to nieco dłużej. Nie możesz też ogolić niczego z nazw opcji. Jednak obsługa IPv6 jest dość trywialna do dodania i kosztuje tylko kilka bajtów kodu więcej (a wtedy regsubpodejście oparte na bazie danych jest równie długie).
Donal Fellows

ahhh, Tcl / Tcl-DP ... niesamowity zestaw narzędzi. (w latach 90. profesor pokazał nam, że możemy napisać Excel w wersji rozproszonej w sieci (z siatką, włącznie z oceną formuł!) współdzielony przez kilka osób z (iirc) 4 (krótkimi) liniami dla serwera i 5 dla klientów. ..
Olivier Dulac

proc s {c a p}czy naprawdę potrzebujesz całej tej białej spacji?
kot

12

Groovy 133 , 125 , 93 , 89

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

Prawdopodobnie tylko IPv4.

Nie golfowany:

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

Testowanie:

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

1
.toInteger()as inti s.inetAddress.address*.toInteger()(s.inetAddress.address as int[]). I po tym jest dodatkowa przestrzeń .with.
manatwork

@manatwork thx! Zaktualizowano
Will Lp

9

Python 3, 170 166 147 bajtów

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()

Włącza port stdin, tylko IPv4. Działa na GNU / Linux (i, jak przypuszczam, na większości innych jednorożców), który automatycznie rozwija „” do „0.0.0.0”, choć nie jestem pewien co do systemu Windows.


2
Możesz zapisać kilka bajtów. Po pierwsze, spacje import *i , SOCK_STREAMsą niepotrzebne. Również linia wysyłania może być napisana bardziej efektywnie jako c.send(b"%d\n"%eval(a[0].replace(".","+"))).
Hannes Karppila

2
@HannesKarppila oh, dzięki. zapomniałem o przestrzeniach, jednak ewidentny hack jest całkiem fajny.
sammko

2
AF_INET i SOCK_STREAM są tylko stałymi; AF_INET ma wartość 2, a SOCK_STREAM ma wartość 1. Ponadto, jak wspomniano, SOCK_STREAM jest niepotrzebny; więc możesz to skrócić, używając zamiast tego s=socket(2).
Skyler

1
nie możesz po prostu zrobić funkcji socket () i tym samym zapisać kolejny bajt?
Foon

1
Możesz zapisać 10 znaków za pomocą Pythona 2. Następnie int(input())staje się, input()a część wysyłająca staje sięc.send(`eval(a[0].replace(".","+"))`)
Blender

9

Java, 371 368 350 344 333 310 295 282 bajtów

Grał w golfa

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]);}}}}

Nie golfił

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]);
            }
        }
    }
}

Wynik

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

1
Usuń int k=i zamień k na wszystkie c w Integer.toString(k). Aby zapisać kilka bajtów.
GiantTree,

1
Java bajt dość pewnie miesza wartość zwracaną dla 192.168.2.1 lub podobnych adresów z bajtem powyżej 127.
AlexR

1
Zmień interfacena classpowinien zyskać jeszcze kilka bajtów
ortis

2
Użyj a.getOutputStream().write((c[0] + c[1] + c[2] + c[3]+"\n").getBytes());zamiastnew DataOutputStream(a.getOutputStream()).writeBytes(c[0] + c[1] + c[2] + c[3] + "\n")
ortis

3
Nie jest try(Socket a=...){}krótszy niż a.close();? Wymaga Java 7, ale może zyskać bajty.
Olivier Grégoire

8

PowerShell v2 +, 303 268 257 227 bajtów

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()}

Zaoszczędziłem 35 bajtów dzięki Mattowi ... Zaoszczędziłem kolejne 11 bajtów przez aliasing New-Objecti drobne poprawki ... Zaoszczędziłem 30 bajtów więcej, domyślnie używając anyadresu localhost zamiast adresu IP, i poprawiłem pod kątem ciągłego używania zgodnie z pierwotnym opisem i spóźniłem się

Naprawdę podobny do odpowiedzi w C # , ponieważ to .NET leży u podstaw obu. Zapisujemy tutaj kilka bajtów nad odpowiedzią C #, mogąc wykorzystać zwracaną funkcjonalność programu PowerShell (otaczanie naszej deklaracji / przypisania w parenach, a następnie natychmiast wywoływać metody.), Ale strasznie dużo tracimy przez konieczność sformułowania podsumowania . Fakt, że mamy nieco krótsze nazwy / połączenia klas, jest naprawdę powodem, dla którego ta odpowiedź pokonuje C #.

Wyjaśnienie

Najpierw tworzymy New-Alias(z nalaliasem), aby zaoszczędzić na ponownym pisaniu New-Objectpóźniej. Reszta pierwszego wiersza to konfiguracja detektora TCP. Podajemy wiersz poleceń $args[0]jako dane wejściowe do utworzenia nowego System.Net.Sockets.TcpListener, zapisanego jako $l. Ten obiekt jest zamknięty w parenach i natychmiast wywoływany za pomocą, .Start()aby aktywnie otwierał gniazdo.

Wchodząc w nieskończoną forpętlę, ustawiamy następnie nasłuchiwanie $lna blokowanie, za pomocą AcceptTcpClient()którego będzie czekać na połączenie. Odwołanie do tego połączenia (po jego ustanowieniu) jest przechowywane $c, enkapsulowane w parens i natychmiast wywoływane, GetStream()aby uzyskać strumień danych. Ten strumień danych jest przekazywany do nowego System.IO.StreamWriterkonstruktora, $wabyśmy mogli nim manipulować. Sam konstruktor jest zamknięty w parens i natychmiast wywoływany Write(...).

W ramach Write(...)połączenia bierzemy uchwyt klienta $ci uzyskujemy jego RemoteEndPointwłasność. Jest to jedyny (jak dotąd znalazłem) sposób uzyskania zdalnego adresu IP. Następnie musimy ponownie rzutować to jako [System.Net.IPEndPoint]obiekt, aby było poprawnie sformatowane, obudowane w parens i wyciągnąć tylko .Addresswłaściwość. Mamy wtedy -replacedosłowne okresy ze znakami plus, a następnie przesuwamy do Invoke-Expression(podobnie jak eval), aby uzyskać nasze podsumowanie.

Po napisaniu We / .Dispose()Wy musimy zadzwonić, aby upewnić się, że strumień danych jest opróżniany do klienta i zamykany. Serwer TCP odrzuca połączenie klienta bez ostrzeżenia, więc w zależności od używanego klienta może w tym momencie zawiesić się na chwilę. Następnie przechodzi przez forpętlę bez prawidłowego zamykania połączeń. Oznacza to również, że przecieka pamięć i system zachowuje się jak szalony, ale nie obchodzi nas to, prawda? Może być jednak konieczne użycie Menedżera zadań, aby zabić proces po zakończeniu uruchamiania serwera. :RE

Również tylko IPv4, ponieważ barki sumowania spektakularnie próbują obsłużyć adres IPv6, ponieważ :nie jest poprawnym operatorem algebraicznym iexdo analizy.


2
„Wycieki pamięci i systemu są szalone” Co, free()po nich masz ? delete[], może? : P
cat

8
@tac Tak, jest cały wachlarz metod .close()i .dispose()metod, których tu nie nazywamy, i które sprawiłyby, że ludzie w Code Review mieliby problemy.
AdmBorkBork

Och, czy PS nie jest GC? A może GC dokonuje ponownego liczenia, a nie analizy zakresu?
kot

@tac Tak, PowerShell ma zbierania śmieci dzięki bazowego systemu .NET. Ale w zależności od tego, jak wywołujesz lub wykorzystujesz ten skrypt, możesz napotkać takie błędy, jak ta, która przecieka pamięć w potoku. Powyższy kod również nie jest bezpieczny dla wątków, dlatego może napotykać na to problemy GC, ponieważ nie zamykamy jawnie gniazda.
AdmBorkBork

1
Podczas testowania nie mogłem tego uruchomić, prawdopodobnie z powodu problemów z zaporą ogniową, których nie mam ochoty naprawiać, więc nie jestem pewien, ale ..... Myślę, że możesz upuścić „System” z większości, jeśli nie ze wszystkich rzutów typu masz tam np [Net.ipaddress]::Any. działa.
Matt

7

PHP, 161 (56?)

To jest mój pierwszy post tutaj. Mam nadzieję, że wszystko pójdzie dobrze :)

<?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);}

Nie golfowany:

<?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
    }

Terminal:

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

Działa to tylko w przypadku IPV4

Edycja : Właśnie zauważyłem, że php obsługuje podstawowy serwer:
zdecydowałem trzymać się oryginalnej liczby znaków, chyba że ktoś potwierdzi, czy dozwolone jest śledzenie :)

test2.php: (możliwe rozwiązanie 56-bajtowe)

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

A następnie rozpocznij obsługę z:

php -S localhost:8080 test2.php

Chrome jako klient zrzut ekranu

Edycja 2: wget jako klient

$ wget -qO- localhost:8080
128

Wiem, że reguły mówią: „Program lub funkcja odczytuje liczbę całkowitą N z argumentów lub standardowego wejścia”, ale czy jest w porządku, jeśli programem w tym przypadku jest sam php? A może używanie wbudowanego serwera w php jest uważane za lukę?
Mikael

Witamy w Programowaniu Puzzle i Code Golf! Twoje 161-bajtowe rozwiązanie wygląda świetnie. Czy 56-bajtowe rozwiązanie, o którym wspomniałeś, jest poniżej test2.php? Jeśli tak, myślę, że musiałbyś zapytać PO, czy uznaliby, że tego rodzaju wbudowane rozwiązanie jest akceptowalne w przypadku tego wyzwania. To jednak nie jest luka.
Alex A.

Powiedziałbym, że użycie wbudowanego serwera TCP byłoby dopuszczalne, ale w tym przypadku mówimy o wbudowanym serwerze HTTP . 56-bajtowe rozwiązanie 1) nic nie robi, jeśli klient tylko się łączy i nic nie wysyła; 2) odsyła tylko „[śr. 30 marca 15:15:02 2016] 127.0.0.1:47974 Nieprawidłowe żądanie (źle sformułowane żądanie HTTP)” bez uruchamiania test2.php w przypadku, gdy klient wysyła na przykład „foo”; 3) wysyła pełny zestaw nagłówków odpowiedzi HTTP przed faktyczną wymaganą odpowiedzią w przypadku, gdy klient wyśle ​​prawidłowe żądanie HTTP.
manatwork

@Alex A. Dziękuję i tak, 56-bajtowe rozwiązanie jest test2.php :)
Mikael

@manatwork Masz rację, ale myślałem, że klient nie jest jasno określony w tym zadaniu. Czy w takim razie można używać przeglądarki jako przeglądarki, czy jeszcze prościej czegoś takiego jak „wget -qO- localhost: 8080”?
Mikael

7

Idź , 359 311

To mój pierwszy program w Go - pozwolił mi odkryć jedną rzecz: zdecydowanie nie jest to dobry język golfowy!

(Uznanie dla @steve, który grał większość w golfa!)

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
Ale z pewnością jest to fajny język do tworzenia serwera TCP!
Numeri

1
Dziwne, otrzymuję wynik 360, gdy łączę się z 192.168.0.67, zamiast 427.
Steve

3
Możesz nazwać pakiety strings + strconv, aby zaoszczędzić kilka bajtów. np. "strings"staje się s "strings"tak, że później strings.Splitstaje się sprawiedliwy s.Split.
steve

1
Jeszcze kilka bajtów ogolił pastebin.com/HY84sazE - zaczyna wyglądać nieco bardziej „grałem” teraz
Steve

2
Jeśli użyjesz import(."pkgname")wszystkich funkcji, zostaną zaimportowane do bieżącej przestrzeni nazw, możesz następnie usunąć prefiks. na przykład. import ."fmt"; Println("foo") Jeśli użyjesz Sscanfz fmtpakietu do parsowania adresu zamiast wyrażenia regularnego, zaoszczędzi ci to kilka kolejnych bajtów, co daje niezłą premię Fprintlnza zwracanie sumy zamiast importowania strconv.
Kristoffer Sall-Storgaard

7

Common Lisp, 110 bajtów

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

Detale

(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
Yay dla Common Lithp!
kot

6

q, 88 bajtów

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: Bierze drugi argument wiersza poleceń (pierwszy "-"mówi, żeby qnie interpretować Njako skrypt / plik) i otwiera port ( "p ").
    • Uwaga: Wywołanie q -p Nustawia port jako Nautomatycznie, ale ponieważ pytanie wydaje się sugerować, że Npowinien to być argument dla programu, a nie samego pliku wykonywalnego, poszedłem dalej.
  • Wewnątrz .z.pgfunkcji, która obsługuje przychodzące żądania, .z.aprzechowuje adres IP jako 32-bitową liczbę całkowitą.
    • "i"$0x0 vsdzieli go na liczby całkowite „składniki” i sumdokonuje sumowania.
    • Na stringkoniec wynik liczbowy i dołącz "\n"do niego, aby powrócić do klienta.
  • .z.ph to kolejna funkcja dla żądań HTTP GET, z dodatkową obsługą do konwersji ciągu wyjściowego na prawidłową odpowiedź HTTP.

Demo - serwer:

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)

Demo - klient (z innej quruchomionej sesji 127.0.0.1):

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

Demo - Klient (od curl):

$ curl localhost:1234
128

$

6

LiveScript, 107 105 bajtów

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

Nic wielkiego do dodania, to tylko podstawowe rzeczy z NodeJS. Punkty stylu dla &1(drugi argument), <|(F # piping, podobnie jak $w Haskell) i biop: (+)w LS jest jak sekcje operatora w Haskell: curry funkcja binarna (która dodaje swoje operandy). Również trochę brudny: /jeśli otrzyma dosłowny ciąg po prawej stronie, podzieli się.


5

Perl, 141 132 + 1 = 133 bajty

Grał w golfa

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

Nie golfił

# 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;
}

Przykład

$ 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.
$

Czy jesteś pewien, że to prawda? Otrzymuję sumę wydrukowaną w terminalu serwera, a nie klienta. W każdym razie możesz usunąć wszystkie nawiasy i zmienić s/\./+/gy/./+/.
manatwork

Ahh, źle przeczytany .. odpowiednio się poprawi i uwzględni twoje dobre t / sugestię.
steve

1
while(1){…}{…;redo}zgodnie ze wspaniałą wskazówką user130144 . I z wyjątkiem wezwania, wszystkie inne nawiasy są niepotrzebne. ->send()
manatwork

4

Python 2, 180 bajtów

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

Przenosi port na standardowe wejście.


4

NodeJS (ES6), 129 118 107 bajtów

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

Działa dla IPv4. Uruchom jakonode server.js <port>


W rzeczywistości nie działa, jeśli serwer używa protokołu IPv6 (jak na przykład mój działa automatycznie), ponieważ c.remoteAddresswtedy byłoby ::ffff:127.0.0.1. (Testowałem na Node v5.9.1).
Frxstrem,

Ponadto nie masz końcowego znaku nowej linii, który powinien zwiększyć twój wynik o 2 bajty.
Frxstrem,

@Frxstrem Whoops, zapomniałem nowej linii. Dodaje jednak tylko 1 bajt dzięki ciągom szablonów. Odnośnie rodziny IP: .listen()najpierw domyślnie ustawiony na IPv4, ale wydaje się, że to błąd lub projekt, że to się zmieniło. Przesyłanie będzie nadal działać poprawnie w nowszych wersjach węzła, gdy protokół IPv6 jest wyłączony na komputerze hosta.
Mwr247,

4

Idź, 211 bajtów

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()}}

Prawdopodobnie można grać w golfa dalej, nie jestem do końca zadowolony ze sposobu, w jaki muszę przeanalizować adres IP, na przykład wygląda to na okropny hack.

Nasłuchuje na IPv4 na porcie podanym jako argument.


4

PowerShell, 208 206 192 152 bajtów

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

informacje o wersji:

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

Dzięki TimmyD za uratowanie mnie 14 bajtów!

Ogromne podziękowania dla TessellatingHeckler za zaoszczędzenie mi 40 bajtów


@ TimmyD ah oops Tęskniłem za tym, że było to konieczne ... naprawione teraz
Nacht

Jednym ze sposobów, w jakie programy mogą pobierać dane wejściowe, jest stdin. przypuszczam, że to konkretne pytanie nie określa tego jako dozwolone, ale jest to ogólna rzecz związana z golfem, która moim zdaniem powinna liczyć na PowerShell. Niestety różni się od bash tym, że nie czeka na dane wejściowe na stdin, jeśli nie podano żadnego.
Nacht

Słusznie. naprawione ponownie
Nacht

W porządku, teraz dla niektórych golfów - spróbuj wykonać następujące czynności w 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
Myślę, że możesz to obniżyć do 152 - upuść nowy obiekt i rzutuj bezpośrednio, pomiń konwersję tablicy bajtów i wykonaj rzut rzutujący inaczej, nie przechowuj $ x w ogóle i upuść pozostałe parametry, aby wysłać (), i to staje się ($t=[net.sockets.tcplistener]$args[0]).start();for(){($z=$t.acceptsocket()).send([char[]]"$($z.remoteendpoint.address-replace"\.","+"|iex)");$z.close()}- co testowałem tylko szybko z łączeniem z netcat, ale wydaje się, że działa tak samo - łącząc się z localhost.
TessellatingHeckler

4

8086 kod maszynowy (16-bit DOS), 163 156 148 148 142 bajtów

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

Równoważny kod zespołu:

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

Zakłada się, że ntcpdrvjest ładowany o INT 0x61(i dowolny odpowiedni sterownik pakietu o 0x60). Kompiluj z fasm tcpserv.asm.

Ma jednak pewne problemy:

  • Nie sprawdza, czy argument jest poprawnym numerem portu, czy w ogóle jest liczbą.
  • Klient musi wysłać co najmniej jeden bajt, ponieważ nie mogę znaleźć innego sposobu, aby stwierdzić, czy klient się połączył.
  • Działa tylko raz i zawiesza się przy drugiej próbie. Działa ponownie po ponownym uruchomieniu.
  • Zwrócona wartość jest uzupełniana lewymi zerami.
  • To jest mój pierwszy wpis w golfa, a także mój pierwszy program 8086 asm. Jestem pewien, że istnieją sposoby na dalszą poprawę tego.

1
Możesz po prostu wysłać zrzut heksowy skompilowanego wyjścia dla 148 bajtów
cat

Czy to jest dozwolone? To uczyniłoby ten wpis nieco bardziej konkurencyjnym ...
user5434231

1
W porządku, zmieniłem wpis na kod maszynowy. Ogoliłem także kilka dodatkowych bajtów, używając xor r,rzamiast mov r,0.
user5434231,

1
Napisałem to na maszynie dos, gdzie są nowe wiersze CR LF, więc po prostu poszedłem z tym. Tak czy inaczej, nie ma sensu liczyć teraz rozmiaru asma, równie dobrze można go trochę wyczyścić i dodać kilka komentarzy.
user5434231,

1
To powinno się tu zdarzyć i to działa; int 0x61zwraca losowy port lokalny w ax. Ale zmienia również nasłuchujący adres IP na jakiś śmieciowy numer ( 4.2.0.0iirc)
5434231

3

Haskell, 216 bajtów

Korzystanie z pakietu „sieci prostego” ( cabal install network-simple). Potrzebuje kilku rozszerzeń języka ( -XOverloadedStrings -XNoMonomorphismRestriction) do pracy.

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)

Istnieje kilka możliwych uproszczeń, w tym zmiana wfunkcji, aby zwracać sumę bezpośrednio zamiast listy, oraz używanie funkcji zamiast programu, dzięki czemu można podać numer portu jako argument. Nie sądzę jednak, żeby to znacznie zmniejszyło rozmiar. Może 20 bajtów?


Miły! Dość, że można jeszcze golić kilka bajtów wyłączony przez zmianę nazwy wdo #, więc w h nstaje się h#ndla oszczędności na 2 bajtów na wykorzystanie.
Actorclavilis

3

Świnka, 114 115 bajtów

Gra w golfa:

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}

Nie golfowany:

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

To jest wersja Mumps InterSystems Caché - jeśli istnieje wersja, która może uzyskać adres TCP krótszy niż ##class(%SYSTEM.TCPDevice).PeerAddr() (ponieważ jest to prawie 1/3 całego programu) , może mieć większą szansę na niektóre z już opublikowanych języków ... ;-)

Edycja: Dzięki @TimmyD - przegapiłem odczyt portu ze STDIN lub argumentów zamiast zostać zakodowanym na stałe. Edytowane; dodał 1 bajt do programu.


@TimmyD - Ach, masz rację. Brakowało tego podczas czytania wymagań. Będzie edytować posthaste.
zmerch

3

C, 535 bajtów

Cóż, ktoś musiał to zrobić.

Dodałem podział jednego wiersza, więc opublikowany kod ma w rzeczywistości 536 znaków.

#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;}

Połącz z gcc [file_name] -o server

Biegnij z ./server [port]

połączyć się z telnet localhost [port]


3
Niezła odpowiedź! Jak wspomniano wcześniej , można zapisać kilka bajtów, używając rzeczywistych wartości dla niektórych stałych, takich jak AF_INET i SOCK_STREAM.
Hannes Karppila

2

Java, 210 bajtów

Gra w golfa:

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());}}};

Rozszerzony:

@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());
      }
    }
}

Jest to zbiór wszystkich wskazówek, które podałem w innych odpowiedziach Java, a także pisania jako funkcji zamiast pełnego programu, który zyskuje około 70 bajtów w porównaniu do programu.


2

Haskell, 326 bajtów

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)

Niestety musiałem użyć, Network.Socketaby uzyskać dostęp do zdalnego adresu IP jako liczby całkowitej zamiast ciągu. Byłoby zapisane dziesiątki znaków, czy mogę po prostu zrobić s <- listenOn (PortNumber n), zamiast jawnie wywołać socket, bindi listenindywidualnie. Ale niestety Network.acceptdaje mi ciąg hosta , a nie liczbę całkowitą adresu IP , więc musiałem się uciekać Network.Socket.accepti przyjaciół.

Ta funkcja fprzyjmuje numer portu jako argument i tworzy snasłuch serwerowy ( ) na tym porcie. Następnie wywołuje funkcję gz gniazdem serwera. gzapętla się na zawsze, akceptując połączenia. Funkcja bpobiera rzeczywisty adres IPv4 i oblicza sumę swoich cyfr.

Jestem pewien, że ktoś może to zrobić lepiej niż ja. Chciałem pochwalić się, jak cholernie łatwe są gniazda w Haskell ... ale potem zawiodłem, ponieważ potrzebuję dostępu do adresu IP, co zwykle nie jest łatwe.


Pakiet „prosty w sieci” zapewnia znacznie ładniejszy interfejs, który przekazuje SockAddr do funkcji, którą mu nadasz, co ułatwia rzeczy. Zobacz moje rozwiązanie, które zamierzam opublikować ...
Jules

Widocznych jest kilka uproszczeń: (1) Uważam, że withSocketsDojest to konieczne tylko w systemie Windows, więc jeśli działa w systemie Linux, można je zignorować; (2) 0xFF to znak dłuższy niż 255; (3) konwersja gniazda na uchwyt i używanie zwykłego IO jest znacznie dłuższe niż używanie Network.Socket.send. Tak, sendjest przestarzałe, ale przyczyna nie jest istotna dla tego scenariusza (dotyczy tylko tekstu spoza ASCII lub danych binarnych), więc użycie go wydaje się uzasadnione.
Jules

Network.accept gives me a host string, not an IP address integerNie można po prostu podzielić ciąg IP na ".", mapfunkcja Haskell jest string-to-numeru nad ciągiem Split i podsumować wyniki?
kot

2

Lua 169 162 160 153 151 148 138 129 bajtów

Wersja golfowa

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

Wymaga zainstalowania Luasocket i interpretera obsługującego etykiety. Przetestowałem to z Luajit i mogę również potwierdzić, że kod nie działa z Lua 5.1.

Wersja bez golfa

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

Edycja 1:

Zmieniono i=({c:getpeername()})[1]na justi=c:getpeername()

Edycja 2:

Usunięto nawiasy klamrowe z instrukcji request.

Edycja 3:

Usunięto nawiasy klamrowe wokół vararg, nieco zmniejszono liczbę bajtów.

Edycja 4:

Usunięto nawias wokół „% d +”, krótszy o 2 bajty.

Edycja 5:

Usunięto niepotrzebną zmienną i.

Edycja 6:

Zmieniono ip z „127.0.0.1” na 0. (Dzięki xyzzy na #lua)

Edycja 7:

Usunięto wywołanie funkcji do liczby tonowej, ponieważ ciągi są automatycznie rzutowane na liczby (dzięki Trebuchette za sugestię, nie wiedziałem o tym)


1
Tylko Lua 5.2 i nowsze etykiety wsparcia, jeśli jesteś ciekawy
Trebuchette

1
Ponadto Lua automatycznie rzutuje ciągi na liczby z +operatorem, abyś mógł je wyjąć tonumber.
Trebuchette

2

Haskell, 185 (+ 19 = 204)? bajty

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)

Pobiera numer portu jako jedną linię na standardowym wejściu; wymaga network-simpleod Cabala.

Jak zwykle w przypadku odpowiedzi Haskell, które nie ograniczają się do czystych funkcji, importszajmują o wiele za dużo bajtów. Końcowy znak nowej linii jest również wart 9 bajtów ...

Nieco podobny do odpowiedzi @ Julesa, ale używam manipulacji ciągiem zamiast operacji bajtowych. I ukradł używane -XOverloadedStringsrozszerzenia, a także, co jest prawdopodobnie wart 19 bajtów extra.


2

C, 243 188 bajtów (lub może 217 162 bajtów)

V2: wyjaśnienia poniżej.

188 bajtów:

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]);}

Nieco ostrożnie 162 bajty:

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]);}

Prawdopodobnie jutro rano więcej golfa. Po tych aktualizacjach posprzątam ten post.


V1:

Ten był naprawdę fajny do gry w golfa.

#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);}}

Działa dla IPv4. Przeważnie jest to prosta implementacja. Trzy główne elementy to

Tworzenie gniazda:

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

Używamy różnych jawnych form stałych AF_INET itp. I wykorzystujemy fakt, że gdy struktura jest inicjowana w C w ten sposób, nieokreślone elementy są ustawiane na zero.

Słuchaj klientów, akceptuj ich i zamykaj ich połączenia:

for (listen (s, 8); c = accept (s, & C, & g); q = fclose (g))

Wreszcie, aby wysłać każdemu klientowi dane:

dla (g = 4; g; q + = C.sin_addr.s_addr >> 8 * - g & 255); fprintf (g = fdopen (c, „w”), „% d \ n”, q);

Adres IP jest przechowywany C.sin_addr.s_addrjako 32-bitowa liczba całkowita, gdzie każdy oktet jest reprezentowany przez jeden z czterech bajtów. Sumujemy te bajty za pomocą pętli for, a następnie drukujemy je do strumienia za pomocą fprintf.

Mam krótsze 217 bajtowe rozwiązanie, ale nie jestem do końca pewien, czy nie narusza to standardowych luk, ponieważ wymaga podania portu jako jednoargumentowego w sieciowej kolejności bajtów jako argumentów wiersza poleceń. Oznacza to, że aby uruchomić serwer na porcie 12345, należy zadzwonić

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

gdzie całkowita liczba 1s wynosi 14640. Mówiąc co najmniej, jest to trochę ... kłopotliwe. Ale tutaj jest tak:

#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

Rakieta, 265 bajtów

#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)))

Nie golfowany:

#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

Współczynnik, 155 146 131 206 206 190 bajtów

Właśnie się wiele nauczyłem o programowaniu gniazd niskopoziomowych. I nie sądzę, bym kiedykolwiek chcesz zrobić to jeszcze raz, bo moja Thr głowa boli.

[ 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 ]

O tak, nawleczone i nie wraca, prawda.


Czy możesz użyć 10 base>zamiast string>number?
fede s.

@fedes. Wow, nigdy nie wiedziałem, że istnieje. Myślę, że pozwoli mi to skrócić wiele moich odpowiedzi w Factor!
kot

I 10 >basedla łańcucha> liczba również.
fede s.

1
@fedes. Ci zasługują na odpowiedź tutaj : D
kot
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.