Basit bir TCP sunucusu


104

N bağlantı noktasında gelen TCP trafiğini dinleyen bir program veya işlev yazın. Basit bir hizmet sunar: gelen bağlantı ve adreslerin IP adres alanlarının toplamını hesaplar.

Program veya fonksiyon, N tamsayısını argümanlardan veya stdin'den okur. N bağlantı noktasında gelen TCP bağlantılarını dinler. Birisi bu bağlantı noktasına bağlandığında, program IP adres alanlarının toplamını hesaplar ve izleyen yeni satırla istemciye geri gönderir ve bağlantıyı kapatır.

  • Bağlantı noktası numarası N geçerli bir bağlantı noktası ve 2 10 <N <2 15
  • Sondaki yeni satır \nveya\r\n
  • IPv4 veya IPv6'yı kullanabilirsiniz. IPv6 adresleri onaltılık biçimde yazıldığından, örneğin aynı biçimde sonuç vermeniz gerekir 2001:0db8:0000:0042:0000:8a2e:0370:7334 => 12ecd.

Bu . Standart kurallar ve boşluklar geçerlidir.

Örnek

Sunucunuzu ile çalıştırın ./server 1234. Sunucu şimdi çalışıyor ve 1234 numaralı bağlantı noktasındaki bağlantıları bekliyor. Sonra bir istemci 127.0.0.1sunucunuza bağlanıyor. Sunucu basit bir hesaplamayı yapar: 127+0+0+1 => 128ve (yeni satır firar ile) müşteriye sonucu gönderir: 128\n. Ardından sunucu bağlantıyı kapatır ve bir sonraki istemciyi bekler.

Liderler Sıralaması

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
İnetd / xinetd veya benzerlerini kullanmasına izin verilir mi?
Dijital Travma,

91
Bunu seviyorum, çünkü golf dillerinin iyi olma ihtimalinin düşük olması bir golf mücadelesi.
isaacg

9
Bir TCP sunucusunun yazması çok kolay bir program olması şaşırtıcı değil, aynı zamanda eğlence için golf alıyorum. Sadece bir embesil gibi FizzBuzz ile mücadeleye geri döneceğim.
MonkeyZeus

17
@isaacg Birisi Mathematica'da yerleşik TCP sunucusunu bulmadan önce sadece bir zaman
Downgoat

3
@ MonkeyZeus Adil olmak gerekirse, burada herhangi bir iyi TCP sunucusu göremezsiniz . TCP'nin tüm karmaşıklıklarını (ve uygulama protokolünüzü) iyi işleyen güvenilir, ölçeklenebilir bir TCP sunucusu yapmak biraz daha zordur: D Protokolün son derece basit olmasına kesinlikle yardımcı olsa da , akışı okumak için bir şey yapmanıza gerek yok saymak için çok fazla TCP sunucusunda kırıldığını gördüm: D
Luaan

Yanıtlar:


57

Bash + netcat + ss +…, 65 60 karakter

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

Ciddi bir çözüm değil, sadece bu olasılığı merak ediyordu.

Sayesinde:

Örnek çalışma:

(terminal 1)

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

(Terminal 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 üzerinde alabilirsiniz ncdan netcat'in geleneksel (hayır, netcat'in-openbsd iyi değil) ve ssgelen iproute2 .


22
Neden ciddi bir çözüm olmadığını söylüyorsun? Beklendiği gibi çalıştığı sürece neden ciddi sayılmaması gerektiğine dair bir neden göremiyorum. Aynı zamanda şu anda oldukça önemli bir marjın en kısa olduğu yer.
Alex A.

Konuyla ilgili en büyük endişe , yapılandırılmış IPv6'ya sahip sistemlerde soket ile ilgili bilgilerin farklı biçimde biçimlendirilebileceğini öğrendiğimde @ JesseSielaff ile tartışma sırasında ortaya çıktı . Test etmek için böyle bir sistem yok. Bunun için CW'ye çevirmenin daha doğru olup olmadığını düşünüyorum.
Manat çalışması 17.03.2007

3
Spesifikasyona dair anlayışım, ikisini de değil, IPv4 veya IPv6'yı desteklemeniz gerektiğidir . IPv4 için çalıştığı sürece, IPv6'yı desteklememesi önemli olmamalıdır, diye düşünürdüm.
Alex A.

1
@AlexA. En azından sanırım sorum öyle söylüyor. Aydınlatmalı mıyım?
Hannes Karppila

@HannesKarppila, sorunuz açık. Olası sorun, çözümümün işletim sisteminin çalışabilmesi için belirli bir şekilde yapılandırılmasını gerektirmesi olabilir. Bu yüzden endişeleniyorum çünkü IPv6 yapılandırılmışsa, kullanıp kullanmamama bakılmaksızın başarısız olabilir. IPv6 yapılandırdı Birisi o kesin anlatabilirim ...
manatwork

23

C #, 284 283 282 278 274 254 bayt

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

Temel bir C # TCP sunucusunun klasik örneği. Test yapmak:

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
Sen kullanarak 1 Byte kaydedebilirsiniz int Mainyerine void Main. Program asla geri dönmediğinden, derleyici returnaçıklama gerektirmez .
raznagul

Ve hayır, sızdırmaz. Aslında kaynakların serbest bırakılması konusunda da oldukça belirleyici. Ayrıca, argüman Startisteğe bağlıdır ve başka bir karakter kaydeder.
Luaan

@Luaan Evet, bu hata ayıklamadan kaldı.
LegionMammal978

Ayrıca şunu kullanabilirsiniz usingüzerinde TcpClientsana üç daha fazla karakter kaydetmek (kullanacağı, {}gelen for) ve aynı yapıyor StreamWriterbir daha saklamalısınız.
Luaan

@Luaan açıkça gerek düzgün çalışması için. FlushStreamWriter
LegionMammal978

22

Linux ELF / x86, 146 bayt

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 baytlık bir ELF başlığı, 32 baytlık bir program başlığı, 111 baytlık program kodu + 3 baytlık kodun başlıkları içinde atlamak için kullanılır.

Minik ELF yürütülebilir nasıl oluşturulacağına dair bilgiler bulunabilir ekmek kutusu 'ın ' Linux için gerçekten Teensy ELF Yürütülebilirler'i oluşturma Üzerine Bir Kasırga Öğreticisi ' .

Linux / i386 , belirli soket çağrısında ( makrolardan gelen ) ve orijinal kütüphane çağrısının argüman alanına bir işaretçi ile gelen socketcall(2)multipleks sistem çağrısını kullanır .ebxSYS_*/usr/include/linux/net.hecx

Yürütülebilir dosyayı küçük tutmak için yapılan bazı şeyler:

  • Linux'un girişte kayıtların sıfır olduğunu, ancak ELF standardının gerektirmediğini (tek şart, giriş EDXnoktalarının bir sonlandırma fonksiyonuna (dinamik linker tarafından yüklenen çalıştırılabilirler için yararlıdır) veya NULL) kabul edildiğini varsayar .
  • Açılışta (genellikle bir kabuk ile) yalnızca açık dosya tanımlayıcılarının 0, 1 ve 2 olduğunu varsayar. Bu, dinleme soketinin fd 3 olacağı ve kabul edilen soketin fd 4 olacağı anlamına gelir.
  • Tam olarak 2 argüman olduğunu varsayar (dahil argv[0]).
  • bind(2), listen(2)Ve için yapılan çağrılar için aynı yığın alanı yeniden kullanılır accept(2).
  • phentsizeVe phnumalanları atlamak için , bir bayt CMPhazırlanır phentsizeve phnumalanları ve alanları anında alan bir operasyona dönüşür ( anarşi golfünde ekmek kutusunun çözümünden 123'e utanmadan çalınan bir numara ).
  • x86 string işlemleri LODS(akümülatöre ve artış / azalma kaynak endeksine yükleme) ve STOS(akümülatörden ve artış / azalma hedef endeksine kaydetme) kısa kod için iyidir.
  • XCHG EAX, regMOV EAX, reg2 bayt alır , karşılaştırıldığında , 1 bayttır.
  • CDQ/CLTD(sign-extend EAXiçine EDX:EAX) EDXkayıt sıfıra 1 bayt yolu olarak kullanılabilir .
  • BSWAPuygulamak için kullanışlıdır htons().

Nasm kaynağı:

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
Bu cevap, takdir edilemez bir yoldur.
Kedi,

16

DüğümJS, 146 134 127 bayt

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

Sonunda bir NodeJS cevabı göndereceğim! IPv4 yalnızca şu anda.

Örnek uygulama: node script.js 1024. Başka bir terminalden:

$ curl 127.0.0.1:1024
128

2
Şu anda 127 byte sayıyorum, ancak '\n'değişmez bir yeni satır içeren bir şablon dizgisiyle değiştirerek onu 126'ya indirebilirsin .
Mwr247

Bir HTTP sunucusu oluşturduğunuzda, yani, teknik olarak bir TCP sunucusu olduğu için bu gereklilikleri ortadan kaldırmaz mıydı, ama sadece TCP modülünü kullanıp kendinize bir karakter kaydedemiyor musunuz?
MayorMonty

14

Tcl, 92

  • @DonalFellows sayesinde 1 bayt kurtarıldı.
proc s {c a p} {puts $c [expr [string map .\ + $a]]
close $c}
socket -server s $argv
vwait f

Oldukça açıklamalı:

socket -server s $argv bağımsız değişkenlerde belirtilen bağlantı noktasında bir dinleme soketi oluşturur.

Her yeni bir bağlantı geldiğinde, proc sbuna kanal, kaynak adresi ve kaynak portu parametre olarak adlandırılır. string mapikame .için +kaynak adresi ve expraritmetik olarak daha sonra sonuç, değerlendirir putsgeri bağlantı kanalı c.

vwait gelen bağlantı olaylarını yakalamak için bir olay döngüsü çalıştırır.


@DonalFellows'a aşağıdakiler için teşekkür ederiz:

IPv6'yı işleyen bir sürüm (Tcl 8.6 gerektirir; fazladan uzunlukların çoğu onaltılık bir yanıt üretmekten kaynaklanıyor):

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
Kullanmak applyhiçbir şeyi kurtarmıyor gibi görünüyor. Ne de tcl::mathop::+ {*}[split $a .]biraz daha uzun olduğu gibi kullanamazsınız . Ayrıca seçenek isimlerinden hiçbir şeyi tıraş edemezsiniz. Ancak, IPv6'yı desteklemesi oldukça önemsizdir ve yalnızca birkaç byte'lık bir kod daha regsubpahalıdır (ve daha sonra temelli bir yaklaşım bu kadar uzun sürer).
Donal Fellows,

ahhh, Tcl / Tcl-DP ... inanılmaz araç demeti. (90'lı yıllarda bir profesör, sunucu için (iirc) 4 (kısa) satırlar ve 5 kişi için paylaşılan, birkaç kişiyle paylaşılan ağa dağıtılmış bir Excel (ızgara ile ve formül değerlendirme dahil!) yazabileceğimizi gösterdi. ..
Olivier Dulac

proc s {c a p}Bütün bu boşluklara gerçekten ihtiyacın var mı?
kedi,

12

Groovy 133 , 125 , 93 , 89

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

Muhtemelen sadece IPv4'tür.

Ungolfed:

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

Test yapmak:

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

1
.toInteger()as intve s.inetAddress.address*.toInteger()(s.inetAddress.address as int[]). Ve sonradan fazladan bir boşluk var .with.
Manatwork 17

@ manatwork thx! Güncellenmiş.
Lp

9

Python 3, 170 166 147 bayt

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

Bağlantı noktasını alır stdin, yalnızca IPv4'ü alır. Windows'tan emin olmasa da "" ile "0.0.0.0" arasında otomatik olarak genişleyen GNU / Linux'ta (ve diğer pek çok birimde varsayıyorum) çalışıyor.


2
Birkaç byte tasarruf edebilirsiniz. Birincisi, boşluklar import *ve , SOCK_STREAMgereksizdir. Ayrıca, gönderme satırı daha verimli bir şekilde yazılabilir c.send(b"%d\n"%eval(a[0].replace(".","+"))).
Hannes Karppila

2
@HannesKarppila oh, teşekkürler. boşlukları unuttum, eval hack olsa da oldukça serin.
sammko

2
AF_INET ve SOCK_STREAM sadece sabittir; AF_INET 2 ve SOCK_STREAM 1'dir. Ayrıca belirtildiği gibi SOCK_STREAM gerekli değildir; Böylece bunu kullanarak kısaltabilirsiniz s=socket(2).
Skyler

1
socket () işlevini yapamaz ve bu nedenle başka bir bayt kaydedemez misiniz?
Foon

1
Python 2'yi kullanarak 10 karakter kaydedebilirsiniz. Sonra, int(input())olur input()ve gönderim parçası olurc.send(`eval(a[0].replace(".","+"))`)
Blender

9

Java, 371 368 350 344 333 310 295 282 bayt

golfed

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

Ungolfed

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

Çıktı

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

1
K'yi çıkarın int k=ve içindeki tüm c şeyleri ile değiştirin Integer.toString(k). Birkaç byte kaydetmek için.
GiantTree

1
Javas byte, 192.168.2.1 veya 127'den yüksek bir byte ile benzer adreslerin dönüş değerini tamamen karışıklığa
uğrattı.

1
Değişim interfaceiçin classbirkaç byte kazanmak gerekir
Ortis

2
Yerine a.getOutputStream().write((c[0] + c[1] + c[2] + c[3]+"\n").getBytes());kullanınnew DataOutputStream(a.getOutputStream()).writeBytes(c[0] + c[1] + c[2] + c[3] + "\n")
ortis

3
Daha try(Socket a=...){}kısa değil a.close();mi? Java 7 gerektirir, ancak bayt kazanabilir.
Olivier Grégoire

8

PowerShell v2 +, 303 268 257 227 bayt

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

Matt sayesinde 35 bayt kurtarıldı ... Diğer ad New-Objectve küçük tweaks'lerle 11 bayt daha kaydedildi ... anyIP adresi yerine localhost kullanarak 30 bayt daha kaydedildi ve sürekli olarak belirtilen şekilde kullanım için hesap düzeltildi ve cevapsız kaldım

C # cevabına gerçekten benziyor , çünkü her ikisinde de .NET var. PowerShell’in dönen işlevinden yararlanarak (parenlerdeki bildirimi / atamamızı çevreleyen ve sonra hemen. Yöntemlerini çağırarak), C # yanıtı üzerinden birkaç bayt tasarruf ediyoruz, ancak toplamı formüle etmek zorunda kalarak çok fazla şey kaybediyoruz . Biraz daha kısa sınıf isimlerimiz / çağrılarımız olması, bu cevabın C # ile atılmasının nedeni.

açıklama

İlk önce daha sonra tekrar yazmaktan tasarruf New-Aliasetmek için bir naltakma ad ( diğer adıyla) oluştururuz New-Object. İlk satırın geri kalanı bir TCP Dinleyici ayarlıyor. Komut satırını , depolanan $args[0]yeni bir yaratma girişi olarak geçiyoruz . Bu nesne parenler içinde enkapsüle edilir ve derhal aktif olarak soketi açması için çağrılır .System.Net.Sockets.TcpListener$l.Start()

Sonsuz bir fordöngüye girdikten sonra dinleyicimizi bir bağlantı için bekleyecek olan $lengellemeye ayarladık AcceptTcpClient(). Bu bağlantıya bir referans (bir kez yapıldıktan sonra) saklanır $c, parenler içinde kapsüllenir ve hemen GetStream()veri akışını almak için çağrılır . Bu veri akışı yeni geçirilir System.IO.StreamWriteryapıcı, $wböylece biz onu manipüle edebilir. Bu yapıcı kendisi parens içinde kapsüllenir ve hemen denir Write(...).

İçinde Write(...)çağrı, bizim müşteri kolu almak $cve müşterinin elde RemoteEndPointözelliği. Uzak IP adresini almanın tek yolu (şimdiye kadar buldum). Daha sonra [System.Net.IPEndPoint], onu bir nesne olarak yeniden düzenlemeliyiz, bu yüzden doğru şekilde biçimlendirilmiş, onu parens içinde kapsüllenmiş ve sadece .Addressözelliği çekmeliyiz . O zaman -replacekelimenin tam anlamıyla artı işaretli dönemler, sonra toplamımızı almak için onu Invoke-Expression(benzer şekilde eval) yönlendiririz.

IO yazdıktan sonra, .Dispose()veri akışının müşteriye gönderildiğinden ve kapatıldığından emin olmak için aramamız gerekir . TCP sunucusu, istemci bağlantısını hiçbir uyarı olmadan bırakır, bu nedenle kullanılan istemciye bağlı olarak bu noktada bir süre bekleyebilir. Daha sonra forbağlantıları düzgün bir şekilde kapatmadan döngüden devam eder . Bu aynı zamanda hafızayı sızdırdığı ve sistemin deliler gibi işlediği anlamına geliyor, ancak bunu umursamıyoruz, değil mi? Yine de, sunucuyu çalıştırmayı tamamladığınızda işlemi sonlandırmak için Görev Yöneticisi'ni kullanmanız gerekebilir. : D

Ayrıca, yalnızca IPv4, toplamı bir IPv6 adresini işlemeye çalıştığını açıkça engellediği için ayrıştırmak :için geçerli bir cebirsel işleci olmadığından iex.


2
“Hafızayı sızdıran ve sistem deli gibi işler” Ne, free()sonra onlardan var mı? delete[], olabilir? : P
kedi

8
@tac Evet, bütün bir yetişme var .close()ve .dispose()havale geçirme Kod İnceleme insanlar neden olacak biz burada demeyeceğiz yöntemleri.
AdmBorkBork

Oh, PS GC'd değil mi? Veya GC yeniden hesap yapar ve kapsam analizi yapmaz mı?
kedi

@tac Evet, PowerShell altta yatan .NET sistemi sayesinde çöp toplama özelliğine sahiptir . Ancak, bu betiği nasıl çağırdığınıza veya kaldıracağınıza bağlı olarak , boru hattında bellek sızdıran bir hatayla karşılaşabilirsiniz. Yukarıdaki kod aynı zamanda güvenli değildir ve soketi açıkça kapatmayacağımızdan GC ile ilgili sorunlara da rastlayabiliriz.
AdmBorkBork

1
Sınama sırasında bunu düzeltemedim, muhtemelen güvenlik duvarı sorunları nedeniyle tamir etmeyi istemiyorum bu yüzden emin olamam ama ..... “Sistem” i tüm tip yayınlar değilse çoğundan düşürebilirim. orada var yani: [Net.ipaddress]::Anyçalışır.
Matt

7

PHP, 161 (56?)

Bu benim buradaki ilk görevim. Umarım bu doğru gider :)

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

Ungolfed:

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

Bu sadece IPV4 için çalışır

Düzenleme : Ben sadece php temel sunucuyu desteklediğini fark ettim:
Birisi aşağıdakilere izin verilip verilmediğini onaylamadıkça orijinal karakter sayımına sadık kalmaya karar verdim :)

test2.php: (olası 56 baytlık çözüm)

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

Ve sonra aşağıdakilerle hizmet vermeye başlayın:

php -S localhost:8080 test2.php

Müşteri olarak Chrome ekran görüntüsü

Düzenleme 2: müşteri olarak yaz

$ wget -qO- localhost:8080
128

Kuralların söylediklerini biliyorum: "Program veya işlev, argümanlardan veya stdin'den N tamsayısını okuyor", ancak bu durumda programın kendisi php ise sorun olur mu? Veya yerleşik sunucu kullanıyorsanız php kaçamak var?
Mikael

Programlama Bulmacaları ve Kod Golf'üne Hoş Geldiniz! 161 baytlık çözümünüz harika görünüyor. Bahsettiğiniz 56 baytlık çözüm mü test2.php? Öyleyse, OP'ye sormak zorunda kalacağınızı düşünüyorum, bu tür bir meydan okuma için bu tür bir yerleşik kabul edip etmediklerini düşünün. Yine de bir kaçamak değil.
Alex A.

Yerleşik bir TCP sunucusu kullanmak kabul edilebilir olur, ancak bu durumda yerleşik bir HTTP sunucusu hakkında konuşuruz . Dolayısıyla 56 bayt çözüm 1) müşteri yalnızca bağlanır ve hiçbir şey göndermezse hiçbir şey yapmaz; 2) müşterinin örneğin “foo” göndermesi durumunda test2.php çalıştırmadan yalnızca [[Çar 30 30 10:15:02 2016] 127.0.0.1:47974 Geçersiz istek (Hatalı Biçimli HTTP isteği) ”gönderir; 3) istemcinin geçerli bir HTTP isteği göndermesi durumunda gerekli olan cevaptan önce tam bir HTTP yanıt başlığı seti gönderir.
Manatwork

@Alex A. Teşekkürler ve evet, 56 baytlık çözüm test2.php altında :)
Mikael

@manatwork Haklısınız, ancak müşterinin bu görevde açıkça belirtilmediğini düşünüyordum. Yani tarayıcı kullanmak ya da istemci olarak "wget ​​-qO- localhost: 8080" gibi bir şey kullanmak daha mı kolay?
Mikael

7

Git , 359 311

Bu Go'daki ilk programım - Bir şeyi keşfetmeme izin verdi: Bu kesinlikle iyi bir golf dili değil!

(Golfün çoğunu kim yaptıysa steve şereflendirir!)

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
Ama kesinlikle bir tcp sunucusu yapmak için güzel bir dil!
Numeri

1
Tuhaf, sonuç 360'a, 427 yerine 192.168.0.67'den bağlandığımda 360 elde ediyorum.
steve

3
Birkaç bayttan tasarruf etmek için dizeleri + strconv paketlerini adlandırabilirsiniz. örneğin "strings"daha s "strings"sonra strings.Splitadil olacak şekilde olur s.Split.
Steve

1
Birkaç daha bayt tıraş pastebin.com/HY84sazE - biraz daha bakmaya başlıyor artık "golfed"
steve

2
Eğer kullanırsanız import(."pkgname")tüm fonksiyonlar için geçerli isim ithal edilecek, daha sonra önek bırakabilirsiniz. Örneğin. import ."fmt"; Println("foo") Eğer kullanırsanız Sscanfgelen fmtadresini ayrıştırmak paketin yerine regex ait bu size sahip güzel ikramiye vererek size bir kaç bayt tasarruf edeceksiniz Fprintlntoplam dönen yerine ithalatı için strconv.
Kristoffer Sall-Storgaard,

7

Ortak Lisp, 110 bayt

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

ayrıntılar

(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
Common Lithp için Yay!
kedi

6

q, 88 bayt

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: İkinci komut satırı argümanını alır (ilki komut dosyası / dosya olarak yorumlanmamasını "-"söyler ) ve onunla bir port ( ) açar . qN"p "
    • Not: Arama q -p N, bağlantı noktasını Notomatik olarak ayarlar , ancak soru Nbunun yürütülebilir programın kendisinden ziyade program için bir argüman olması gerektiğini gösteriyor gibi göründüğü için , daha uzun yoldan gittim.
  • .z.pgGelen istekleri işleyen fonksiyonun içinde .z.aIP adresini 32 bit tam sayı olarak tutar.
    • "i"$0x0 vsonu 'tamsayıları' tamsayısına böler sumve toplamı yapar.
    • Son olarak, stringsayısal sonuç ve "\n"istemciye geri dönmek için buna ekleyin .
  • .z.ph Dize çıkışını geçerli bir HTTP yanıtına dönüştürmek için fazladan işlem gerektiren HTTP GET istekleri için başka bir işlevdir.

Demo - Sunucu:

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 - Müşteri ( qçalışan başka bir oturumdan 127.0.0.1):

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

Demo - Müşteri (den curl):

$ curl localhost:1234
128

$

6

LiveScript, 107 105 bayt

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

Eklemek için fazla bir şey yok, sadece temel NodeJS şeyler. &1(İkinci argüman), <|(F # borulaması, $Haskell'da (+)olduğu gibi ) ve biop için stil noktaları : LS'de Haskell'deki operatör bölümleri gibidir : Kıvrımlı bir ikili fonksiyon (işlenenlerini ekler). Ayrıca biraz kirli: /Eğer bir değişmez dize sağında verilirse , bölünür.


5

Perl, 141 132 + 1 = 133 bayt

golfed

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

Ungolfed

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

Örnek

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

Bunun doğru olduğuna emin misin? Müşterinin değil, sunucunun terminalinde yazdırılan tutarı alıyorum. Her neyse, tüm parantezleri kaldırabilir ve s/\./+/g→ değiştirebilirsiniz y/./+/.
Manat işi 18.08

Ahh, yanlış okumak ... buna göre gözden geçirin ve iyi y / önerinizi ekleyin.
steve

1
while(1){…}{…;redo}göre user130144 'in büyük ucu . Ve ->send()çağrı dışında, diğer tüm parantezler gereksizdir.
Manat çalışması

4

Python 2,180 bayt

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

Limanı stdin üzerinden alıyor.


4

DüğümJS (ES6), 129 118 107 bayt

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

IPv4 için çalışıyor. Olarak çalıştırmaknode server.js <port>


Çünkü Aslında, (mayın otomatik yapar, örneğin, gibi) işe sunucunun kullanarak IPv6 eğer gelmez c.remoteAddresso zaman olurdu ::ffff:127.0.0.1. (Düğüm v5.9.1'de test ettim).
Frxstrem

Ayrıca puanınızı 2 bayt artırması gereken son bir yeni hattınız yok.
Frxstrem

@ Frxstrem Whoops, bu yeni satırı unuttum. Şablon dizeleri sayesinde yalnızca 1 bayt ekler. IP ailesiyle ilgili olarak: .listen()önce IPv4'e varsayılan olarak kullanılır, ancak bunun hata veya tasarımla değiştiği görülür. Sunum, ana makinede IPv6 devre dışı bırakıldığında düğümün daha yeni sürümlerinde düzgün çalışacaktır.
Mwr247

4

Git, 211 bayt

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

Muhtemelen daha fazla golf oynayabilir, mesela IP adresini ayrıştırmak zorunda kalmamdan tamamen memnun değilim, örneğin korkunç bir kesmek gibi görünüyor.

Argüman olarak verilen porttaki IPv4'ü dinler.


4

PowerShell, 208 206 192 152 bayt

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

versiyon bilgisi:

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

Beni 14 bayt kurtardığın için TimmyD'ye teşekkürler!

Beni 40 bayttan kurtardığı için TessellatingHeckler'e çok teşekkürler


@TimmyD ah oops Bu gerekli olduğunu özledim ... şimdi düzeltildi
Nacht

Programların girdi almasına izin verilen yollardan biri stdin'dir. Sanırım bu özel soru, izin verildiği gibi belirtilmiyor ancak bu PowerShell için sayılması gerektiğini düşündüğüm genel bir kod golfü. Hiçbiri sağlanmadıysa, basd'den stdin'e girdi beklememesi farklıdır.
Nacht

yeterince adil. tekrar düzeltildi
Nacht

Alrighty, şimdi bazı golf ($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()}
oyuncuları için

1
Sanırım bunu 152'ye indirebilir - yeni nesneyi bırakabilir ve doğrudan yayınlayabilir, bayt dizisi dönüşümünü atlayabilir ve farklı bir dizge oluşturabilir, $ x saklamayın ve kalan parametreleri bırakarak (), ve haline gelir ($t=[net.sockets.tcplistener]$args[0]).start();for(){($z=$t.acceptsocket()).send([char[]]"$($z.remoteendpoint.address-replace"\.","+"|iex)");$z.close()}- ki bu sadece netcat bağlantısıyla hızlı bir şekilde test ettik, ancak aynı şekilde çalışıyor gibi görünüyor - yine de localhost'tan bağlantı kurmak.
TessellatingHeckler

4

8086 makine kodu (16 bit DOS), 163 156 148 148 142 bayt

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

Eşdeğer montaj kodu:

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

Bu varsayımlar ntcpdrvyüklenmiştir INT 0x61(ve uygun olan herhangi bir paket sürücüsünde 0x60). İle derleyin fasm tcpserv.asm.

Yine de bazı sorunları var:

  • Argümanın geçerli bir port numarası olup olmadığını veya bir sayı olup olmadığını kontrol etmez.
  • Müşterinin en az bir bayt göndermesi gerekir, çünkü müşterinin bağlı olup olmadığını söylemenin başka bir yolunu bulamıyorum.
  • Yalnızca bir kez çalışır ve ikinci bir girişimde kilitlenir. Yeniden başlatmanın ardından tekrar çalışır.
  • Dönen değer, sıfırlarla doldurulur.
  • Bu benim ilk kod golf girişim ve aynı zamanda ilk 8086 asm programım. Bunu daha da iyileştirmenin yolları olduğuna eminim.

1
Sadece derlenen çıktının hexdump'ını 148 byte için gönderebilirsiniz
cat

Buna izin var mı? Bu girişi biraz daha rekabetçi yapar ...
user5434231

1
Tamam, girişi makine koduyla değiştirdim. Ayrıca xor r,rbunun yerine birkaç bayt daha tıraş mov r,0.
user5434231

1
Newline'ların olduğu bir dos makinesine yazdım CR LF, o yüzden onunla gittim. Her iki durumda da, şimdi asm boyutunu saymak biraz anlamsız, biraz temizleyip bir yorum eklemek kadar iyi olabilir.
user5434231

1
Bunun da burada olması gerekiyor ve işe yarıyor; int 0x61içinde rasgele bir yerel bağlantı noktası döndürür ax. Ama aynı zamanda, dinleme IP'sini bazı çöp numaralarına ( 4.2.0.0iirc) değiştirir
user5434231

3

Haskell, 216 bayt

"Network-simple" paketini ( cabal install network-simple) kullanarak. -XOverloadedStrings -XNoMonomorphismRestrictionÇalışması için birkaç dil uzantısına ( ) ihtiyaç var.

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)

wToplamı liste yerine doğrudan döndürme işlevini değiştirme ve bağlantı noktası numarasının argüman olarak belirtilebilmesi için program yerine işlev kullanma da dahil olmak üzere birkaç olası basitleştirme vardır . Yine de, bunun büyüklüğü azaltacağını hayal etmiyorum. Belki 20 bayt?


Güzel! Hala yeniden adlandırarak kapalı birkaç byte tıraş edebilirsiniz eminim wiçin #, bu nedenle w h nolur h#nKullanım başına 2 bayt tasarruf için.
Actorclavilis

3

Kabakulak, 114 115 Bayt

golfed:

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}

Ungolfed:

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

Bu, Mumps'un InterSystems Caché versiyonudur - eğer TCP adresini alabilecek bir versiyon varsa ##class(%SYSTEM.TCPDevice).PeerAddr() (programın neredeyse 1 / 3'ü kadar), zaten yayınlanan diğer dillerden bazılarına karşı daha iyi bir şansa sahip olabilir. ... ;-)

Düzenleme: @TimmyD sayesinde - Sabit kodlama yerine portun STDIN'den veya argümanlardan okumasını özledim. Düzenlenen; programa 1 bayt ekledi.


@TimmyD - Ah, haklısın. Gereksinimleri okurken bunu kaçırdım. Posthaste düzenler.
zmerch

3

C, 535 bayt

Birisi bunu yapmak zorundaydı.

Gönderilen kodun aslında 536 karakterden oluşması için tek bir satır sonu ekledim.

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

ile derlemek gcc [file_name] -o server

koşmak ./server [port]

ile bağlantı telnet localhost [port]


3
Güzel cevap! Daha önce de belirtildiği gibi, AF_INET ve SOCK_STREAM gibi bazı sabitler için gerçek değerleri kullanarak birkaç bayttan tasarruf edebilirsiniz.
Hannes Karppila

2

Java, 210 bayt

golfed:

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

Expanded:

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

Bu, diğer Java cevaplarında verdiğim tüm ipuçlarının yanı sıra, programla karşılaştırıldığında kabaca 70 bayt kazandıran, tam bir program yerine bir fonksiyon olarak yazma işlevidir.


2

Haskell, 326 bayt

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)

Ne yazık ki Network.Socketuzak IP adresine erişmek için bir dize yerine bir tamsayı olarak kullanmak zorunda kaldım. Sadece yapabileceğini eğer karakterlerin onlarca kaydedilmiş olurdu s <- listenOn (PortNumber n)doğrusu açıkça çağırmak zorunda kalmak yerine socket, bindve listenayrı ayrı. Ancak, ne yazık ki, Network.acceptbana bir IP adresi tamsayı değil bir ana bilgisayar dizesi verir , bu yüzden başvurmak zorunda kaldım ve arkadaşlarım.Network.Socket.accept

İşlev fbir port numarasını argüman olarak alır ve so portu dinleyen bir sunucu soketi ( ) oluşturur . Ardından işlevi gsunucu soketi ile çağırır . gsonsuza kadar döngüler, bağlantıları kabul etmek. İşlev bgerçek bir IPv4 adresini alır ve sayılarının toplamını hesaplar.

Eminim bir yerlerde birileri bunu benden daha iyi yapabilir. Haskell'de ne kadar kolay soket işlerinin ne kadar kolay olduğunu göstermek istedim ... ama sonra perişan oldular, çünkü genellikle elde etmesi kolay olmayan IP adresine erişmem gerekiyor.


"Ağ-basit" paketi, SockAddr'yi verdiğiniz bir işleve geçiren ve işleri kolaylaştıran çok daha hoş bir arayüz sağlar.
Jules

Bazı basitleştirmeler açıktır: (1) withSocketsDoSadece Windows için gerekli olduğuna inanıyorum , bu nedenle Linux'ta çalışıyorsa göz ardı edilebilir; (2) 0xFF, 255'ten daha uzun bir karakterdir; (3) soketi bir tutamağa dönüştürmek ve normal IO kullanmak kullanmaktan çok daha uzundur Network.Socket.send. Evet, sendkullanımdan kaldırıldı, ancak nedeni bu senaryo ile ilgili değil (yalnızca ASCII dışı metin veya ikili verilerle ilgilidir), bu nedenle kullanımı makul görünüyor.
Jules

Network.accept gives me a host string, not an IP address integerSadece IP dize bölemezsiniz ".", mapbölünmüş dize üzerinde Haskell'ın dizeden sayı fonksiyonu ve sonuçlarını toplar?
kedi,

2

Lua, 169 162 160 153 151 148 138 129 bayt

Golf versiyonu

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'ın kurulmasını ve etiketleri destekleyen bir tercüman olmasını gerektirir. Luajit ile test ettim ve ayrıca kodun Lua 5.1 ile çalışmadığını doğrulayabilirim.

Ungolfed versiyonu

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

Düzenleme 1:

i=({c:getpeername()})[1]Sadece olarak değiştirildii=c:getpeername()

Düzenleme 2:

Require ifadesinden kaldırılan parantezler.

Düzenleme 3:

Vararg etrafındaki parantezler çıkarıldı, bayt sayısı biraz azaldı.

4'ü Düzenle:

"% D +" etrafındaki parantezi 2 bayt kısa kaldırıldı.

Düzenle 5:

Gereksiz değişken i kaldırıldı.

Düzenle 6:

IP’yi "127.0.0.1" den 0 a değiştirdik.

Düzenleme 7:

Dizeler otomatik olarak sayılara çevrildiğinden işlev çağrısı tonara kaldırıldı (Öneri için Trebuchette sayesinde bunu bilmiyordum)


1
Merak ediyorsanız, yalnızca Lua 5.2 ve üzeri destek etiketleri
Trebuchette

1
Ayrıca, Lua otomatik olarak karakterleri rakamlarla +operatöre aktarır, böylece çıkarabilirsiniz tonumber.
Trebuchette

2

Haskell, 185 (+ 19 = 204)? bayt

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)

Port numarasını stdin'de bir satır olarak alır; network-simpleCabal'dan gerektirir .

Haskell’de her zaman olduğu gibi, kendilerini saf işlevlerle sınırlandırmayan cevaplar, importsçok fazla bayt alır. Sondaki yeni satır 9 bayt değerinde ...

@ Jules'ın cevabına biraz benzeyen, ancak bayt işlemleri yerine dize işleme kullanıyorum. Ben çaldı kullanılan -XOverloadedStringsmuhtemelen ekstra 19 byte değerinde olan yanı uzantısı.


2

C, 243 188 bayt (veya belki 217 162 bayt)

V2: açıklamalar için aşağıya bakınız.

188 bayt:

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

Biraz baypas 162 bayt:

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

Muhtemelen yarın sabah golf oynamak mümkün. Bu güncellemelerden sonra bu yazıyı toparlayacağım.


V1:

Bu bir golf için gerçekten çok eğlenceliydi.

#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 için çalışıyor. Çoğunlukla basit bir uygulamadır. Üç ana bileşen

Soket oluşturma:

yapı sockaddr_in S = {2, htons (atoi (v [1]))}, C; bağla (s = soket (2,1,0), & S, g = 16);

AF_INET etc sabitlerinin çeşitli açık biçimlerini kullanıyoruz ve bir yapı C ile ilk kez başlatıldığında, belirtilmeyen öğelerin sıfıra ayarlanmış olmasını kullanıyoruz.

Müşterileri dinleyin, kabul edin ve bağlantılarını kapatın:

için () = C (s, C kabul & g s, 8) (dinlemek q = fclose (g))

Son olarak, her müşteriye veriyi göndermek için:

(g = 4 g, q + = C.sin_addr.s_addr >> 8 * - g 255); fprintf (g = fdopen (c, "W"), "% d \ n", k);

IP C.sin_addr.s_addrher sekizlinin dört bayttan biri tarafından temsil edildiği 32 bitlik bir tamsayı olarak depolanır . Bu baytları for döngüsüyle toplarız ve sonra bunları fprintf kullanarak akışa yazdırırız.

Daha kısa bir 217 baytlık çözümüm var, ancak standart boşlukları ihlal etmediğinden tam olarak emin değilim, çünkü bağlantı noktasının ağ satır baytında komut satırı argümanları olarak unary olarak verilmesini gerektiriyor. Yani sunucuyu 12345 portunda çalıştırmak için bir çağrı yapmanız gerekecek.

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

Toplam 1s 14640 olduğu. En az söylemek biraz ... hantal. Ama yine de burada:

#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

Raket, 265 bayt

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

Ungolfed:

#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

Faktör, 155 146 131 206 190 bayt

Düşük seviye soket programlaması hakkında çok şey öğrendim. Benim çünkü şimdiye kadar istiyorum bir daha yapma sanmıyorum thr başım ağrıyor.

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

Oh evet, dişli ve geri dönmüyor, doğru.


Eğer kullanabilir miyim 10 base>yerine string>number?
fede s.

@fedes. Vay, bunun var olduğunu asla bilmiyordum. Bunun Faktör cevaplarımın çoğunu kısaltmama izin vereceğini düşünüyorum!
kedi

Ve 10 >basesayı> string için de.
fede s.

1
@fedes. Bunlar burada bir cevabı hak ediyor : D
kedi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.