เซิร์ฟเวอร์ TCP แบบง่าย


104

เขียนโปรแกรมหรือฟังก์ชั่นที่รับฟังทราฟฟิก TCP ขาเข้าบนพอร์ต N มันให้บริการง่ายๆ: คำนวณผลรวมของฟิลด์ที่อยู่ IP ของการเชื่อมต่อขาเข้าและส่งคืน

โปรแกรมหรือฟังก์ชั่นอ่านจำนวนเต็ม N จากการขัดแย้งหรือ stdin มันฟังการเชื่อมต่อ TCP ขาเข้าบนพอร์ต N เมื่อมีคนเชื่อมต่อกับพอร์ตนั้นโปรแกรมจะคำนวณผลรวมของฟิลด์ที่อยู่ IP และส่งกลับไปยังไคลเอนต์ด้วยการขึ้นบรรทัดใหม่และปิดการเชื่อมต่อ

  • หมายเลขพอร์ต N เป็นพอร์ตที่ถูกต้องและ 2 10 <N <2 15
  • ขึ้นบรรทัดใหม่สามารถเป็นได้ทั้ง\nหรือ\r\n
  • คุณสามารถใช้ IPv4 หรือ IPv6 เนื่องจากที่อยู่ IPv6 ถูกเขียนในรูปแบบเลขฐานสิบหกคุณจึงต้องให้ผลลัพธ์ในรูปแบบเดียวกันเช่น2001:0db8:0000:0042:0000:8a2e:0370:7334 => 12ecdกัน

นี่คือรหัสกอล์ฟใช้กฎมาตรฐานและช่องโหว่

ตัวอย่าง

./server 1234คุณเรียกใช้เซิร์ฟเวอร์ของคุณกับ เซิร์ฟเวอร์กำลังทำงานและรอการเชื่อมต่อที่พอร์ต 1234 จากนั้นไคลเอ็นต์127.0.0.1จะเชื่อมต่อกับเซิร์ฟเวอร์ของคุณ เซิร์ฟเวอร์ของคุณมีประสิทธิภาพการคำนวณง่ายๆ127+0+0+1 => 128และส่งผลไปยังลูกค้า 128\n(มีต่อท้ายบรรทัดใหม่): จากนั้นเซิร์ฟเวอร์จะปิดการเชื่อมต่อและรอลูกค้ารายต่อไป

ลีดเดอร์บอร์ด

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


1
มันอนุญาตให้ใช้ inetd / xinetd หรือคล้ายกัน?
บาดเจ็บทางดิจิทัล

91
ฉันชอบสิ่งนี้เนื่องจากมันเป็นความท้าทายด้านการเล่นกอล์ฟที่ภาษาการเล่นกอล์ฟไม่น่าจะเก่งนัก
isaacg

9
ไม่เพียงเป็นเรื่องที่น่าอัศจรรย์ที่เซิร์ฟเวอร์ TCP นั้นเป็นโปรแกรมที่ง่ายต่อการเขียน แต่ฉันปูพื้นอย่างละเอียดด้วยข้อเท็จจริงที่ว่ามันกำลังเล่นกอล์ฟเพื่อความสนุก ฉันจะกลับไปดิ้นรนกับ FizzBuzz เหมือนคนโง่
MonkeyZeus

17
@isaacg ถึงเวลาก่อนที่จะมีคนค้นพบเซิร์ฟเวอร์ TCP ในตัว Mathematica
Downgoat

3
@MonkeyZeus เพื่อความยุติธรรมคุณจะไม่เห็นเซิร์ฟเวอร์ TCP ที่ดีที่นี่ การสร้างเซิร์ฟเวอร์ TCP ที่เชื่อถือได้และปรับขนาดได้ซึ่งจัดการความซับซ้อนทั้งหมดของ TCP (และโปรโตคอลแอปพลิเคชันของคุณ) ได้ดีขึ้นเล็กน้อย: D แม้ว่ามันจะช่วยได้อย่างแน่นอนว่าโปรโตคอลนั้นง่ายมาก - คุณไม่จำเป็นต้องอ่านสตรีม ที่ฉันเห็นว่ามีเซิร์ฟเวอร์ TCP จำนวนมากเกินไปที่จะนับ: D
Luaan

คำตอบ:


57

Bash + netcat + ss + …, 65 60 ตัวอักษร

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

ไม่ใช่วิธีการแก้ปัญหาที่ร้ายแรงเพียงแค่อยากรู้เกี่ยวกับความเป็นไปได้นี้

ขอบคุณที่:

  • ninjaljสำหรับการแนะนำการawkกรองพื้นฐาน (-5 ตัวอักษร)

วิ่งตัวอย่าง:

(อาคาร 1)

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

(อาคาร 2)

bash-4.3$ nc localhost 8080
128

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

บน Ubuntu คุณจะได้รับncจากnetcat แบบดั้งเดิม (ไม่มี netcat-OpenBSD ไม่ดี) และssจากiproute2


22
ทำไมคุณถึงบอกว่ามันไม่ใช่ทางออกที่จริงจัง? ตราบใดที่มันใช้งานได้ตามที่คาดหวังฉันก็ไม่เห็นเหตุผลว่าทำไมมันไม่ควรได้รับการพิจารณาอย่างจริงจัง นอกจากนี้ยังสั้นที่สุดด้วยอัตรากำไรอย่างมีนัยสำคัญในขณะนี้
Alex A.

ความกังวลที่ใหญ่ที่สุดที่เกิดขึ้นระหว่างการสนทนากับ @JesseSielaffเมื่อฉันได้เรียนรู้ว่าในระบบที่มีการกำหนดค่า IPv6 ข้อมูลที่เกี่ยวข้องกับซ็อกเก็ตอาจถูกจัดรูปแบบแตกต่างกัน ไม่มีระบบดังกล่าวเพื่อทดสอบ ที่ฉันคิดว่าจะถูกต้องมากขึ้นเพื่อเปลี่ยนเป็น CW
จัดการ

3
ความเข้าใจของฉันเกี่ยวกับข้อมูลจำเพาะคือคุณต้องรองรับ IPv4 หรือ IPv6 ไม่ใช่ทั้งสองอย่าง ดังนั้นตราบใดที่ทำงานกับ IPv4 ไม่สนับสนุน IPv6 ก็ไม่เป็นไร
Alex A.

1
@AlexA อย่างน้อยฉันก็คิดว่าคำถามของฉันพูดอย่างนั้น ฉันควรอธิบายให้ชัดเจนหรือไม่
Hannes Karppila

@ HannesKarppila คำถามของคุณชัดเจน ปัญหาที่เป็นไปได้คือโซลูชันของฉันอาจต้องกำหนดค่าระบบปฏิบัติการในวิธีการเฉพาะเพื่อให้สามารถเรียกใช้ ดังนั้นฉันกังวลเพราะอาจล้มเหลวหากมีการกำหนดค่า IPv6 ไม่ว่าฉันจะจัดการหรือไม่ก็ตาม ใครบางคนที่มีการกำหนดค่า IPv6 สามารถบอกได้อย่างแน่นอน…
manatwork

23

C #, 284 283 282 278 274 254 ไบต์

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

ตัวอย่างคลาสสิกของเซิร์ฟเวอร์ C # TCP พื้นฐาน การทดสอบ:

อาคาร 1:

$ ./Q76379.exe 1029

อาคาร 2:

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

Firefox:


7
คุณสามารถบันทึก 1 ไบต์โดยใช้แทนint Main void Mainเนื่องจากโปรแกรมไม่ส่งคืนคอมไพเลอร์ไม่จำเป็นต้องมีreturnคำสั่ง
raznagul

และไม่มันไม่รั่วไหล จริงๆแล้วมันค่อนข้างกำหนดเกี่ยวกับการปล่อยทรัพยากรเช่นกัน นอกจากนี้อาร์กิวเมนต์ยังStartเป็นทางเลือกบันทึกอักขระอื่น
Luaan

@ Luaan ใช่นั่นเป็นสิ่งที่เหลือจากการดีบัก
LegionMammal978

นอกจากนี้คุณสามารถใช้usingบนTcpClientซึ่งจะช่วยให้คุณสามตัวละครเพิ่มเติม (ใช้{}จากfor) และทำเช่นเดียวกันกับStreamWriterควรจะบันทึกอีกหนึ่ง
Luaan

@Luaan ฉันต้องชัดเจนที่จะทำให้มันทำงานอย่างถูกต้อง FlushStreamWriter
LegionMammal978

22

Linux ELF / x86, 146 ไบต์

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

รวมส่วนหัว ELF 52- ไบต์ส่วนหัวโปรแกรม 32- ไบต์รหัสโปรแกรม 111 ไบต์ + รหัส 3 ไบต์เพื่อข้ามไปรอบ ๆ ด้านในของส่วนหัว

ข้อมูลเกี่ยวกับวิธีการสร้าง executables เอลฟ์ขนาดเล็กที่สามารถพบได้ที่ขนมปัง 's ' ลมกรดสอนในการสร้างจริงๆ teensy ELF Executables สำหรับลินุกซ์ '

Linux / i386 ใช้การsocketcall(2)เรียกระบบหลายระบบซึ่งใช้ในebxการเรียกซ็อกเก็ตเฉพาะ ( SYS_*มาโครจาก/usr/include/linux/net.h) และในecxตัวชี้ไปยังพื้นที่อาร์กิวเมนต์ของการเรียกใช้ไลบรารีต้นฉบับ

มีบางสิ่งที่ทำเพื่อให้ไฟล์ปฏิบัติการเล็ก:

  • มันถือว่าการลงทะเบียนเป็นศูนย์ในรายการซึ่ง Linux ทำ แต่ไม่จำเป็นต้องใช้โดยมาตรฐาน ELF (ข้อกำหนดเพียงอย่างเดียวคือที่EDXจุดเข้าสู่ funtion ขั้นสุดท้าย (มีประโยชน์สำหรับ executables ที่โหลดโดย dynamic linker) หรือเป็น NULL)
  • มันถือว่าเป็นการเปิดตัว (โดยทั่วไปคือเชลล์) ตัวอธิบายไฟล์แบบเปิดเพียงอย่างเดียวคือ 0, 1 และ 2 ซึ่งหมายความว่าซ็อกเก็ตการฟังจะเป็น fd 3 และซ็อกเก็ตที่ยอมรับจะเป็น fd 4
  • มันถือว่ามีข้อโต้แย้ง 2 ประการ (รวมถึงargv[0])
  • พื้นที่สแต็คเดียวกันจะนำกลับมาใช้สำหรับการโทรไปbind(2), และlisten(2)accept(2)
  • หากต้องการข้ามข้ามphentsizeและphnumเขตข้อมูลไบต์จะถูกเตรียมไว้ล่วงหน้ากลายเป็นการCMPดำเนินการที่ใช้เวลาphentsizeและphnumเขตข้อมูลเป็นทันที (ถูกขโมยอย่างไม่น่าเชื่อจากโซลูชันของ breadbox ถึง 123 ในสนามกอล์ฟแบบอนาธิปไตย )
  • การดำเนินการสตริง x86 LODS(โหลดเข้าสู่การสะสมและดัชนีแหล่งที่มาเพิ่มขึ้น / ลดลง) และSTOS(เก็บจากการสะสมและดัชนีปลายทางที่เพิ่มขึ้น / ลดลง) จะดีสำหรับรหัสสั้น ๆ
  • XCHG EAX, regคือ 1 ไบต์เปรียบเทียบกับMOV EAX, regซึ่งใช้เวลา 2 ไบต์
  • CDQ/CLTD(sign-กางEAXเข้าไปEDX:EAX) สามารถใช้เป็นวิธี 1 ไบต์เพื่อเป็นศูนย์การEDXลงทะเบียน
  • BSWAPhtons()จะเป็นประโยชน์สำหรับการดำเนินการ

แหล่งที่มาของ 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
คำตอบนี้เป็นวิธี underappreciated
แมว

16

โหนด, 146 134 127 ไบต์

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

ในที่สุดฉันก็โพสต์คำตอบ NodeJS! IPv4 เฉพาะตอนนี้

ตัวอย่างการดำเนินการ: node script.js 1024. จากเทอร์มินัลอื่น:

$ curl 127.0.0.1:1024
128

2
ฉันนับ 127 ไบต์ในขณะนี้แม้ว่าคุณจะได้รับถึง 126 โดยการแลกเปลี่ยน'\n'กับสตริงแม่แบบที่มีขึ้นบรรทัดใหม่ตามตัวอักษร
Mwr247

สิ่งนี้จะไม่เป็นไปตามข้อกำหนดหรือไม่เพราะคุณสร้างเซิร์ฟเวอร์ HTTP ฉันหมายถึงมันเป็นเทคนิคเซิร์ฟเวอร์ TCP แต่คุณไม่สามารถใช้โมดูล TCP และช่วยตัวคุณเองได้ใช่ไหม
MayorMonty

14

Tcl, 92

  • บันทึก 1 ไบต์ขอบคุณ @DonalFellows
proc s {c a p} {puts $c [expr [string map .\ + $a]]
close $c}
socket -server s $argv
vwait f

ค่อนข้างอธิบายตนเอง:

socket -server s $argv สร้างซ็อกเก็ตฟังบนพอร์ตที่ระบุไว้ในข้อโต้แย้ง

ทุกครั้งที่มีการเชื่อมต่อใหม่proc sจะมีการเรียกใช้โดยมีช่องสัญญาณแหล่งที่อยู่และแหล่งที่มาของพอร์ตเป็นพารามิเตอร์ string mapทดแทน.สำหรับ+ในแหล่งที่อยู่และexprarithmetically ประเมินผลซึ่งเป็นแล้วกลับไปยังช่องทางในการเชื่อมต่อputsc

vwait เรียกใช้วนรอบเหตุการณ์เพื่อตรวจจับเหตุการณ์การเชื่อมต่อที่เข้ามา


ให้เครดิตกับ @DonalFellows สำหรับสิ่งต่อไปนี้:

นี่คือรุ่นที่จัดการกับ IPv6 (ต้องมี Tcl 8.6 ความยาวส่วนใหญ่เป็นพิเศษเกิดจากการตอบสนองแบบเลขฐานสิบหก):

Tcl, 109

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

1
การใช้applyดูเหมือนจะไม่บันทึกอะไรเลย คุณไม่สามารถใช้งานได้tcl::mathop::+ {*}[split $a .]เพราะใช้งานนานกว่าเล็กน้อย คุณไม่สามารถโกนหนวดอะไรก็ได้จากชื่อตัวเลือก แต่การสนับสนุน IPv6 นั้นค่อนข้างน่าสนใจในการเพิ่มและมีค่าใช้จ่ายโค้ดเพียงไม่กี่ไบต์เท่านั้น (จากนั้นregsubวิธีการแบบต่อฐานจะใช้เวลานาน)
Donal Fellows

ahhh, Tcl / Tcl-DP ... เครื่องมือที่น่าทึ่งมากมาย (ในยุค 90 อาจารย์แสดงให้เราเห็นว่าเราสามารถเขียน Excel แบบกระจายเครือข่าย (มีกริดและรวมถึงการประเมินสูตร!) แบ่งปันกันในหมู่หลาย ๆ คนด้วยเส้น (iirc) 4 (สั้น) สำหรับเซิร์ฟเวอร์และ 5 สำหรับลูกค้า ..
Olivier Dulac

proc s {c a p}คุณต้องการทุกสิ่งที่ช่องว่างหรือไม่
แมว

12

Groovy 133 , 125 , 93 , 89

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

อาจเป็น IPv4 เท่านั้น

Ungolfed:

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

การทดสอบ:

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

1
.toInteger()as intและ→s.inetAddress.address*.toInteger() (s.inetAddress.address as int[])และมีพื้นที่พิเศษหลังจาก.withนั้น
ฝีมือ

@ จัดการงานขอบคุณ! Updated
จะ Lp

9

Python 3, 170 166 147 ไบต์

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

ใช้พอร์ตเปิดstdinเฉพาะ IPv4 ใช้งานได้กับ GNU / Linux (และฉันถือว่าเป็น Unices อื่น ๆ ส่วนใหญ่) ซึ่งจะขยาย "" เป็น "0.0.0.0" โดยอัตโนมัติ แต่ไม่แน่ใจเกี่ยวกับ Windows


2
คุณสามารถบันทึกได้หลายไบต์ ประการแรกช่องว่างในimport *และ, SOCK_STREAMไม่จำเป็น นอกจากนี้ยังสามารถเขียนบรรทัดส่งได้อย่างมีประสิทธิภาพมากขึ้นเช่นc.send(b"%d\n"%eval(a[0].replace(".","+")))กัน
Hannes Karppila

2
@ HannesKarppila โอ้ขอบคุณ ลืมช่องว่างแฮ็ค eval นั้นค่อนข้างเท่ห์
sammko

2
AF_INET และ SOCK_STREAM เป็นค่าคงที่เท่านั้น AF_INET คือ 2 และ SOCK_STREAM คือ 1 นอกจากนี้ตามที่กล่าวมา SOCK_STREAM นั้นไม่จำเป็น s=socket(2)เพื่อให้คุณสามารถร่นว่าด้วยการแทนการใช้
Skyler

1
คุณไม่สามารถทำ socket () แล้วจึงบันทึกไบต์อื่นได้หรือไม่
Foon

1
คุณสามารถบันทึก 10 ตัวอักษรโดยใช้ Python 2 จากนั้นint(input())จะกลายเป็นinput()และส่วนส่งกลายเป็นc.send(`eval(a[0].replace(".","+"))`)
Blender

9

Java, 371 368 350 344 333 310 295 282 ไบต์

แข็งแรงเล่นกอล์ฟ

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

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

เอาท์พุต

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

1
ลบint k=และแทนที่ k ด้วยสิ่ง c Integer.toString(k)ทั้งหมด เพื่อประหยัดไม่กี่ไบต์
GiantTree

1
Javas byte แน่ใจว่าสวย messes ขึ้นค่าตอบแทนสำหรับ 192.168.2.1 หรือคล้ายกันกับ adresses ไบต์เหนือ 127
AlexR

1
เปลี่ยนinterfaceไปclassควรได้รับอีกไม่กี่ไบต์
ORTIS

2
ใช้a.getOutputStream().write((c[0] + c[1] + c[2] + c[3]+"\n").getBytes());แทนnew DataOutputStream(a.getOutputStream()).writeBytes(c[0] + c[1] + c[2] + c[3] + "\n")
ortis

3
ไม่try(Socket a=...){}สั้นกว่านี้a.close();หรือ ต้องการ Java 7 แต่สามารถรับได้เป็นไบต์
Olivier Grégoire

8

PowerShell v2 +, 303 268 257 227 ไบต์

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

บันทึก 35 ไบต์ด้วยแมตต์ ... บันทึกอีก 11 ไบต์โดยใช้นามแฝงNew-Objectและปรับแต่งเล็กน้อย ... บันทึกอีก 30 ไบต์โดยปริยายโดยใช้ localhost แทนที่anyอยู่ IP และแก้ไขเพื่อการใช้งานอย่างต่อเนื่องตามที่ระบุไว้เดิมและฉันพลาด

คล้ายกับคำตอบ C # จริงๆ เนื่องจากเป็น. NET พื้นฐานทั้งสอง เราบันทึกสองสามไบต์ที่นี่เหนือคำตอบ C # โดยสามารถใช้ประโยชน์จากฟังก์ชันการส่งคืนของ PowerShell (โดยรอบการประกาศ / การมอบหมายของเราใน parens แล้วเรียกวิธีการ.) แต่เราเสียล็อตที่แย่มากโดยต้องการกำหนดผลรวม . ความจริงที่ว่าเรามีชื่อ / การเรียกชั้นสั้นกว่าเล็กน้อยคือจริงๆแล้วทำไมคำตอบนี้จึงเต้น C #

คำอธิบาย

เราสร้าง a New-Alias(พร้อมnalนามแฝง) เพื่อบันทึกในการพิมพ์อีกครั้งในNew-Objectภายหลัง ส่วนที่เหลือของบรรทัดแรกคือการตั้งค่า TCP Listener เราผ่านบรรทัดคำสั่ง$args[0]เป็น input สำหรับการสร้างใหม่System.Net.Sockets.TcpListener, $lเก็บไว้เป็น วัตถุนั้นถูกห่อหุ้มด้วย parens และเรียกใช้ทันที.Start()เพื่อเปิดซ็อกเก็ต

เข้าสู่forวงวนไม่สิ้นสุดจากนั้นเราตั้งค่าให้ผู้ฟังของเรา$lปิดกั้นด้วยAcceptTcpClient()ซึ่งจะรอการเชื่อมต่อ การอ้างอิงถึงการเชื่อมต่อนั้น (เมื่อทำแล้ว) จะถูกเก็บไว้ใน$cห่อหุ้มด้วย parens และเรียกทันทีGetStream()เพื่อรับสตรีมข้อมูล datastream ที่ถูกส่งผ่านไปอยู่ที่ใหม่System.IO.StreamWriterปลูกสร้าง$wเพื่อให้เราสามารถจัดการกับมัน สร้างที่อยู่ในตัวของมันเองห่อหุ้มใน parens Write(...)และเรียกทันที

ภายในการWrite(...)โทรเราจัดการลูกค้าของเรา$cและรับRemoteEndPointทรัพย์สินของลูกค้า นี่เป็นวิธีเดียว (ที่ฉันพบมาแล้ว) เพื่อรับที่อยู่ IP ระยะไกล ต่อไปเราต้องทำการแคสต์อีกครั้งว่าเป็น[System.Net.IPEndPoint]วัตถุดังนั้นจึงจัดรูปแบบอย่างถูกต้องห่อหุ้มสิ่งนั้นไว้ใน parens และดึง.Addressคุณสมบัติออกมา จากนั้นเรา-replaceใช้ช่วงเวลาตามตัวอักษรพร้อมกับเครื่องหมายบวกแล้วส่งไปที่Invoke-Expression(คล้ายกับeval) เพื่อรับผลรวมของเรา

หลังจากการเขียน IO เราต้องโทรหา.Dispose()เพื่อให้แน่ใจว่าดาต้าสตรีมถูกล้างออกไปยังไคลเอนต์และปิด เซิร์ฟเวอร์ TCP จะปล่อยการเชื่อมต่อไคลเอ็นต์โดยไม่มีการเตือนดังนั้นขึ้นอยู่กับไคลเอนต์ที่ใช้มันอาจหยุดทำงานชั่วขณะหนึ่ง ณ จุดนี้ จากนั้นจะดำเนินการต่อผ่านforลูปโดยไม่ต้องปิดการเชื่อมต่ออย่างถูกต้อง นี่ก็หมายความว่ามันรั่วความทรงจำและระบบจัดการอย่างบ้าคลั่ง แต่เราไม่สนใจหรอกใช่มั้ย คุณอาจต้องใช้ตัวจัดการงานเพื่อฆ่ากระบวนการเมื่อคุณรันเซิร์ฟเวอร์เสร็จแล้ว : D

นอกจากนี้ IPv4 เท่านั้นเนื่องจาก baration summation พยายามที่จะจัดการกับที่อยู่ IPv6 อย่างน่าทึ่งเนื่องจาก:ไม่ใช่ผู้ประกอบการพีชคณิตที่ถูกต้องที่iexจะแยกวิเคราะห์


2
"หน่วยความจำรั่วและระบบการจัดการอย่างบ้าคลั่ง"สิ่งที่คุณจะต้องfree()พวกเขาหลังจากที่? delete[], อาจจะ? : P
cat

8
@tac ใช่มีการฆ่าของทั้ง.close()และ.dispose()วิธีการที่เราไม่ได้เรียกร้องที่นี่ที่จะทำให้คนในรหัสตรวจสอบจะมีพอดี
AdmBorkBork

โอ้ GC GC'd ไม่ใช่เหรอ? หรือ GC ทำการคำนวณซ้ำและไม่วิเคราะห์ขอบเขต?
แมว

@tac ใช่ PowerShell มีการรวบรวมขยะด้วยระบบ. NET พื้นฐาน แต่ขึ้นอยู่กับว่าคุณโทรหรือใช้ประโยชน์จากสคริปต์นี้คุณสามารถใช้เป็นข้อบกพร่องเช่นนี้หน่วยความจำรั่วในท่อ รหัสด้านบนยังไม่ปลอดภัยสำหรับเธรดและสามารถพบปัญหา GC กับสิ่งนั้นได้เนื่องจากเราไม่ได้ปิดซ็อกเก็ตอย่างชัดเจน
AdmBorkBork

1
ในการทดสอบฉันไม่สามารถใช้งานได้อาจเกิดจากปัญหาไฟร์วอลล์ที่ฉันไม่รู้สึกเหมือนกำลังแก้ไขดังนั้นฉันไม่แน่ใจ แต่ ..... ฉันคิดว่าคุณสามารถวาง "ระบบ" จากส่วนใหญ่ถ้าไม่ใช่ทุกประเภท cast คุณมีเช่น: [Net.ipaddress]::Anyงาน
Matt

7

PHP, 161 (56?)

นี่คือโพสต์แรกของฉันที่นี่ ฉันหวังว่ามันจะถูกต้อง :)

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

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
    }

เทอร์มิ:

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

ใช้งานได้กับ IPV4 เท่านั้น

แก้ไข : ฉันเพิ่งสังเกตเห็นว่า php รองรับเซิร์ฟเวอร์พื้นฐาน:
ฉันตัดสินใจที่จะนับจำนวนตัวอักษรดั้งเดิมเว้นแต่มีใครบางคนยืนยันถ้าอนุญาตดังต่อไปนี้ :)

test2.php: (วิธีแก้ปัญหา 56- ไบต์ที่เป็นไปได้)

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

จากนั้นเริ่มให้บริการด้วย:

php -S localhost:8080 test2.php

Chrome ในฐานะลูกค้า ภาพหน้าจอ

แก้ไข 2: wget ในฐานะลูกค้า

$ wget -qO- localhost:8080
128

ฉันรู้ว่ากฎพูดว่า: "โปรแกรมหรือฟังก์ชั่นอ่านจำนวนเต็ม N จากการขัดแย้งหรือ stdin" แต่มันก็โอเคถ้าโปรแกรมในกรณีนี้เป็น php ตัวเอง? หรือใช้เซิร์ฟเวอร์ builtin ใน php ถือว่าเป็นช่องโหว่หรือไม่
Mikael

ยินดีต้อนรับสู่ Programming Puzzles & Code Golf! 161-byte solution ของคุณดูดีมาก คุณใช้วิธีแบบ 56 ไบต์test2.phpหรือไม่? ถ้าเป็นเช่นนั้นฉันคิดว่าคุณต้องถาม OP ว่าพวกเขาจะพิจารณาประเภทของการยอมรับในตัวสำหรับความท้าทายนี้หรือไม่ มันไม่ใช่ช่องโหว่
Alex A.

ผมจะบอกว่าใช้ builtin เซิร์ฟเวอร์ TCPจะเป็นที่ยอมรับ แต่ในกรณีนี้เราพูดคุยเกี่ยวกับ builtin เซิร์ฟเวอร์ HTTP ดังนั้นโซลูชั่น 56 ไบต์ 1) ไม่ทำอะไรเลยหากลูกค้าเชื่อมต่อและส่งสิ่งใด 2) ส่งกลับเฉพาะ“ [พุธ 30 มีนาคม, 2016] 127.0.0.1:47974 คำขอไม่ถูกต้อง (คำขอ HTTP ที่มีรูปแบบไม่ถูกต้อง)” โดยไม่เรียกใช้ test2.php ในกรณีที่ลูกค้าส่งตัวอย่างเช่น“ foo”; 3) ส่งส่วนหัวการตอบกลับ HTTP แบบเต็มก่อนการตอบสนองที่ต้องการจริงในกรณีที่ลูกค้าส่งการร้องขอ HTTP ที่ถูกต้อง
จัดการ

@Alex A. ขอบคุณและใช่วิธีแก้ปัญหา 56- ไบต์อยู่ภายใต้ test2.php :)
มิคาเอล

@ การจัดการคุณถูกต้อง แต่ฉันคิดว่าลูกค้าไม่ได้ระบุไว้อย่างชัดเจนในงานนี้ ดังนั้นมันก็โอเคที่จะใช้เบราว์เซอร์หรือสิ่งที่ง่ายกว่าเช่น "wget ​​-qO- localhost: 8080" ในฐานะลูกค้า?
Mikael

7

ไป , 359 311

นี่เป็นโปรแกรมแรกของฉันใน Go - อนุญาตให้ฉันค้นพบสิ่งหนึ่ง: นี่ไม่ใช่ภาษากอล์ฟที่ดีแน่นอน!

(ความรุ่งโรจน์ถึง @steve ผู้ที่เล่นกอล์ฟเป็นส่วนใหญ่!)

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

2
แต่แน่ใจว่าเป็นภาษาที่ดีสำหรับการทำเซิร์ฟเวอร์ tcp!
ตัวเลข

1
แปลกที่ฉันได้ผลลัพธ์ 360 เมื่อฉันเชื่อมต่อจาก 192.168.0.67 แทนที่จะเป็น 427
steve

3
คุณสามารถตั้งชื่อชุดของสตริง + strconv เพื่อบันทึกไม่กี่ไบต์ เช่น"strings"กลายเป็นs "strings"เพื่อที่ว่าต่อมาจะกลายเป็นเพียงstrings.Split s.Split
สตีฟ

1
มีอีกไม่กี่ไบต์ที่จะวางpastebin.com/HY84sazE - เริ่มที่จะมองหา "golfed" อีกสักครู่
steve

2
หากคุณใช้import(."pkgname")ฟังก์ชั่นทั้งหมดจะถูกนำเข้าสู่เนมสเปซปัจจุบันจากนั้นคุณสามารถวางคำนำหน้า เช่น. import ."fmt"; Println("foo") ถ้าคุณใช้Sscanfจากfmtแพคเกจที่จะแยกอยู่แทน regex มันจะช่วยให้คุณประหยัดไม่กี่ไบต์อื่นให้คุณโบนัสที่ดีของการมีกลับทั้งหมดแทนการนำเข้าFprintln strconv
Kristoffer Sall-Storgaard

7

Lisp สามัญ, 110 ไบต์

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

รายละเอียด

(use-package 'usocket)

(lambda (port)

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

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

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

2
Yay สำหรับ Lithp สามัญ!
แมว

6

q, 88 ไบต์

system raze"p ",1_.z.x;.z.pg:{(string sum"i"$0x0 vs .z.a),"\n"};.z.ph:{.h.hy[`;.z.pg[]]}
  • system raze"p ",1_.z.x: ใช้อาร์กิวเมนต์บรรทัดคำสั่งที่สอง (อันแรก"-"คือเพื่อบอกqไม่ให้ตีความNเป็นสคริปต์ / ไฟล์) และเปิดพอร์ต ( "p ") ด้วย
    • หมายเหตุ: การโทรq -p Nจะตั้งค่าพอร์ตNโดยอัตโนมัติ แต่เนื่องจากคำถามดูเหมือนว่าจะแนะนำว่าNควรเป็นข้อโต้แย้งกับโปรแกรมมากกว่าการปฏิบัติการเองฉันเลยไปไกลกว่านี้
  • ภายใน.z.pgฟังก์ชั่นที่จัดการคำขอที่เข้ามา.z.aถือ IP แอดเดรสเป็นจำนวนเต็ม 32 บิต
    • "i"$0x0 vsแยกมันออกเป็น 'ส่วนประกอบ' ของจำนวนเต็มและsumทำการรวม
    • สุดท้ายstringผลตัวเลขและต่อท้าย"\n"เพื่อกลับไปยังลูกค้า
  • .z.ph เป็นอีกฟังก์ชั่นสำหรับคำขอ HTTP GET พร้อมการจัดการพิเศษเพื่อแปลงเอาต์พุตสตริงเป็นการตอบสนอง HTTP ที่ถูกต้อง

สาธิต - เซิร์ฟเวอร์:

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

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

การสาธิต - ไคลเอนต์ (จากqเซสชันอื่นที่ทำงานอยู่127.0.0.1):

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

การสาธิต - ลูกค้า (จากcurl):

$ curl localhost:1234
128

$

6

LiveScript, 107 105 ไบต์

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

ไม่ต้องเพิ่มอะไรมากมันเป็นเพียงพื้นฐานของ NodeJS คะแนนสไตล์สำหรับ&1(อาร์กิวเมนต์ที่สอง), <|(F # piping, คล้ายกับ$ใน Haskell) และ biop: (+)ใน LS เป็นเหมือนส่วนของโอเปอเรเตอร์ใน Haskell: ฟังก์ชันไบนารี curried (ที่เพิ่มตัวถูกดำเนินการ) ยังสกปรกเล็กน้อย: /ถ้าให้สายตัวอักษรทางด้านขวาจะแยก


5

Perl, 141 132 + 1 = 133 ไบต์

แข็งแรงเล่นกอล์ฟ

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

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

ตัวอย่าง

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

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

คุณแน่ใจหรือไม่ว่าถูกต้อง? ฉันได้รับผลรวมที่พิมพ์ในเทอร์มินัลของเซิร์ฟเวอร์ไม่ใช่ของลูกค้า อย่างไรก็ตามคุณสามารถลบวงเล็บทั้งหมดและเปลี่ยน→s/\./+/g y/./+/
จัดการ

อ่าอ่านผิด .. จะแก้ไขให้ถูกต้องและรวมเอา y / คำแนะนำที่ดีของคุณ
สตีฟ

1
while(1){…}{…;redo}ตามuser130144ดี 's ปลาย และยกเว้นการ->send()โทรวงเล็บอื่น ๆ ทั้งหมดนั้นไม่จำเป็น
จัดการ


4

NodeJS (ES6), 129 118 107 ไบต์

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

ทำงานได้กับ IPv4 ทำงานเป็นnode server.js <port>


ที่จริงแล้วใช้ไม่ได้หากเซิร์ฟเวอร์ใช้ IPv6 (เช่นของฉันจะทำงานโดยอัตโนมัติ) เนื่องจากc.remoteAddressจะเป็น::ffff:127.0.0.1เช่นนั้น (ฉันทดสอบกับโหนด v5.9.1)
Frxstrem

นอกจากนี้คุณยังไม่ได้ขึ้นบรรทัดใหม่ซึ่งควรเพิ่มคะแนนของคุณเป็น 2 ไบต์
Frxstrem

@Frxstrem อ๊ะลืมบรรทัดใหม่นั้น เพิ่มเพียง 1 ไบต์ แต่ต้องขอบคุณเทมเพลตสตริง เกี่ยวกับตระกูล IP: .listen()ใช้เพื่อเริ่มต้นกับ IPv4 ก่อน แต่ดูเหมือนว่าจะเกิดจากข้อผิดพลาดหรือการออกแบบที่มีการเปลี่ยนแปลง การส่งจะยังคงทำงานได้อย่างถูกต้องบนโหนดรุ่นใหม่กว่าเมื่อปิดใช้งาน IPv6 บนเครื่องโฮสต์
Mwr247

4

ไปขนาด 211 ไบต์

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

อาจจะสามารถเล่นกอล์ฟต่อไปได้ฉันไม่พอใจอย่างสิ้นเชิงกับวิธีที่ฉันต้องแยกที่อยู่ IP เช่นดูเหมือนแฮ็คที่น่ากลัว

ฟัง IPv4 บนพอร์ตที่กำหนดเป็นอาร์กิวเมนต์


4

PowerShell, 208 206 192 152 ไบต์

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

ข้อมูลรุ่น:

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

ขอบคุณ TimmyD ที่ช่วยฉัน 14 ไบต์!

ขอบคุณมากสำหรับ TessellatingHeckler ที่ช่วยฉันได้ 40 ไบต์


@ TimmyD อาโอ๊ะฉันพลาดไปแล้วว่ามันจำเป็น ... แก้ไขแล้วตอนนี้
Nacht

หนึ่งในวิธีที่โปรแกรมอนุญาตให้รับอินพุตคือจาก stdin ฉันคิดว่าคำถามนี้ไม่ได้ระบุว่าอนุญาต แต่เป็นสิ่งที่รหัสกอล์ฟทั่วไปที่ฉันคิดว่าควรนับสำหรับ PowerShell มันน่าเสียดายที่แตกต่างจากทุบตีซึ่งไม่ต้องรออินพุตจาก stdin หากยังไม่ได้ให้
Nacht

ยุติธรรมพอสมควร แก้ไขอีกครั้ง
Nacht

เอาล่ะตอนนี้สำหรับบางกอล์ฟลองต่อไปนี้ที่ 192 -($t=new-object net.sockets.tcplistener($args[0])).start();for(){($z=$t.acceptsocket()).send(($x=[byte[]][char[]](""+($z.remoteendpoint.address-replace"\.","+"|iex))+32),$x.count,0);$z.close()}
AdmBorkBork

1
ฉันคิดว่าคุณสามารถเคาะลงได้ถึง 152 - ปล่อยวัตถุใหม่และส่งโดยตรงข้ามการแปลงอาร์เรย์ไบต์และทำสตริงที่แตกต่างกันอย่าเก็บ $ x เลยและวางพารามิเตอร์ที่เหลือเพื่อส่ง () และมัน กลายเป็น($t=[net.sockets.tcplistener]$args[0]).start();for(){($z=$t.acceptsocket()).send([char[]]"$($z.remoteendpoint.address-replace"\.","+"|iex)");$z.close()}- ซึ่งฉันเพิ่งทดสอบอย่างรวดเร็วด้วยการเชื่อมต่อ netcat แต่ดูเหมือนว่าจะทำงานได้เหมือนกัน - การเชื่อมต่อจาก localhost อยู่ดี
TessellatingHeckler

4

รหัสเครื่อง 8086 (DOS แบบ 16 บิต), 163 156 148 148 142 ไบต์

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

รหัสแอสเซมบลีที่เทียบเท่า:

org 0x100
tcp equ 0x61    ; NTCPDRV interrupt

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

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

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

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

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

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

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

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

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

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

    mov ax,0x4c00
    int 0x21

สมมติฐานนี้ntcpdrvถูกโหลดที่INT 0x61(และไดรเวอร์แพ็คเก็ตที่เหมาะสมที่0x60) fasm tcpserv.asmคอมไพล์ด้วย

มันมีปัญหาบางอย่างแม้ว่า:

  • ไม่ได้ตรวจสอบว่าอาร์กิวเมนต์เป็นหมายเลขพอร์ตที่ถูกต้องหรือไม่หรือแม้แต่เป็นตัวเลขเลย
  • ลูกค้าจะต้องส่งอย่างน้อยหนึ่งไบต์เนื่องจากฉันไม่สามารถหาวิธีอื่นเพื่อบอกได้ว่าลูกค้ามีการเชื่อมต่อหรือไม่
  • ใช้งานได้เพียงครั้งเดียวและค้างในครั้งที่สอง ทำงานได้อีกครั้งหลังจากรีบูต
  • ค่าที่ส่งคืนจะถูกเสริมด้วยศูนย์
  • นี่คือรายการรหัสกอล์ฟครั้งแรกของฉันและเป็นโปรแกรม asm 8086 แรกของฉัน ฉันแน่ใจว่ามีวิธีการปรับปรุงนี้เพิ่มเติม

1
คุณสามารถโพสต์ hexdump ของผลลัพธ์ที่คอมไพล์สำหรับ 148 bytes
cat

อนุญาตหรือไม่ มันจะทำให้รายการนี้มีการแข่งขันมากขึ้น ...
user5434231

1
เอาล่ะฉันได้เปลี่ยนรายการเป็นรหัสเครื่อง นอกจากนี้ยังโกนไบต์อีกไม่กี่ปิดโดยใช้แทนxor r,r mov r,0
user5434231

1
ฉันเขียนมันลงในเครื่อง DOS ที่มีบรรทัดใหม่CR LFดังนั้นฉันจึงไปกับมัน ไม่ว่าจะเป็นวิธีใดก็ตามนับไม่ถ้วนที่จะนับขนาด asm ในขณะนี้อาจทำความสะอาดได้เล็กน้อยและเพิ่มความคิดเห็น
user5434231

1
นั่นควรจะเกิดขึ้นที่นี่ด้วยและมันก็ใช้ได้ ผลตอบแทนพอร์ตท้องถิ่นสุ่มint 0x61 axแต่มันยังเปลี่ยน IP การฟังไปเป็นหมายเลขขยะบางส่วน ( 4.2.0.0iirc)
user5434231

3

Haskell, 216 ไบต์

การใช้แพ็คเกจ "network-simple" ( cabal install network-simple) ต้องการนามสกุลภาษาสองสามอัน ( -XOverloadedStrings -XNoMonomorphismRestriction) ในการทำงาน

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

มีความเรียบง่ายที่เป็นไปได้สองสามอย่างรวมถึงการเปลี่ยนwฟังก์ชั่นเพื่อส่งคืนผลรวมโดยตรงแทนที่จะเป็นรายการและใช้ฟังก์ชั่นแทนโปรแกรมเพื่อให้สามารถระบุหมายเลขพอร์ตเป็นอาร์กิวเมนต์ได้ ฉันไม่คิดว่ามันจะลดขนาดได้มากนัก บางที 20 ไบต์?


ดี! ค่อนข้างมั่นใจว่าคุณยังคงสามารถโกนไม่กี่ไบต์ออกโดยการเปลี่ยนชื่อwไป#เพื่อให้w h nกลายเป็นh#nเงินฝากออมทรัพย์ 2 ไบต์ต่อการใช้งาน
Actorclavilis

3

คางทูม114 114ไบต์

แข็งแรงเล่นกอล์ฟ:

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

นี่คือ Mumps รุ่น InterSystems Caché - หากมีรุ่นออกมาที่สามารถรับที่อยู่ TCP สั้นกว่า##class(%SYSTEM.TCPDevice).PeerAddr() (เนื่องจากเกือบ 1 ใน 3 ของโปรแกรมทั้งหมด)อาจมีโอกาสที่ดีกว่าเมื่อเทียบกับภาษาอื่น ๆ ที่โพสต์ไว้แล้ว ... ;-)

แก้ไข: ขอบคุณ @TimmyD - ฉันพลาดการอ่านพอร์ตจาก STDIN หรืออาร์กิวเมนต์แทนที่จะเป็นฮาร์ดโค้ด แก้ไข; มันเพิ่ม 1 ไบต์ในโปรแกรม


@TimmyD - โอ้คุณถูกต้องแล้ว พลาดที่อ่านผ่านข้อกำหนด จะแก้ไขโพสต์ทู
zmerch

3

C, 535 ไบต์

มีคนต้องทำเช่นนี้

ฉันได้เพิ่มตัวแบ่งบรรทัดเดียวดังนั้นรหัสที่โพสต์จริง ๆ มี 536 ตัวอักษร

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

รวบรวมกับ gcc [file_name] -o server

ทำงานด้วย ./server [port]

เชื่อมต่อกับ telnet localhost [port]


3
คำตอบที่ดี! ดังที่ได้กล่าวไว้ก่อนหน้านี้คุณสามารถบันทึกสองสามไบต์โดยใช้ค่าจริงสำหรับค่าคงที่บางค่าเช่น AF_INET และ SOCK_STREAM
Hannes Karppila

2

Java, 210 ไบต์

แข็งแรงเล่นกอล์ฟ:

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

ขยาย:

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

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

การรวบรวมเคล็ดลับทั้งหมดที่ฉันให้ไว้ในคำตอบ Java อื่น ๆ รวมทั้งการเขียนเป็นฟังก์ชันแทนที่จะเป็นโปรแกรมเต็มรูปแบบซึ่งได้รับประมาณ 70 ไบต์เมื่อเทียบกับโปรแกรม


2

Haskell, 326 ไบต์

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

น่าเศร้าที่ฉันต้องใช้Network.Socketเพื่อเข้าถึงที่อยู่ IP ระยะไกลเป็นจำนวนเต็มแทนที่จะเป็นสตริง มันจะได้บันทึกไว้หลายสิบตัวอักษรถ้าฉันเพียงแค่จะทำs <- listenOn (PortNumber n)มากกว่าต้องเรียกอย่างชัดเจนsocket, bindและlistenเป็นรายบุคคล แต่น่าเศร้าที่Network.acceptให้สตริงโฮสต์ไม่ใช่เลขจำนวนเต็มที่อยู่ IP ดังนั้นฉันต้องหันไปหาNetwork.Socket.acceptเพื่อน

ฟังก์ชั่นfใช้หมายเลขพอร์ตเป็นอาร์กิวเมนต์และสร้างเซิร์ฟเวอร์ซ็อกเก็ต ( s) ฟังพอร์ตนั้น จากนั้นเรียกใช้ฟังก์ชันgด้วยซ็อกเก็ตเซิร์ฟเวอร์ gวนซ้ำไปเรื่อย ๆ ยอมรับการเชื่อมต่อ ฟังก์ชันbใช้ที่อยู่ IPv4 จริงและคำนวณผลรวมของตัวเลข

ฉันแน่ใจว่าบางคนสามารถทำได้ดีกว่าฉัน ฉันต้องการแสดงให้เห็นว่าซ็อกเก็ตง่าย ๆ ที่ถูกสาปนั้นอยู่ใน Haskell ... แต่ก็ล้มเหลวอย่างน่าสังเวชเพราะฉันต้องการเข้าถึงที่อยู่ IP ซึ่งโดยทั่วไปไม่สะดวก


แพ็คเกจ "network-simple" มอบอินเตอร์เฟสที่ดีกว่าซึ่งส่งผ่าน SockAddr ไปยังฟังก์ชันที่คุณให้ซึ่งจะทำให้ง่ายขึ้น ดูโซลูชันของฉันที่ฉันกำลังจะโพสต์ ...
Jules

มีการทำให้เข้าใจง่ายขึ้นเล็กน้อย: (1) ฉันเชื่อว่าwithSocketsDoจำเป็นสำหรับ Windows เท่านั้นดังนั้นหากใช้งานบน Linux จะสามารถเพิกเฉยได้ (2) 0xFF เป็นอักขระที่ยาวกว่า 255; (3) การแปลงซ็อกเก็ตเป็นจุดจับและการใช้ IO ปกติจะนานกว่าการใช้Network.Socket.sendมาก ใช่sendเลิกใช้แล้ว แต่เหตุผลไม่เกี่ยวข้องกับสถานการณ์นี้ (เกี่ยวข้องกับข้อความหรือข้อมูลไบนารีที่ไม่ใช่ ASCII เท่านั้น) ดังนั้นจึงสมเหตุสมผลที่จะใช้
Jules

Network.accept gives me a host string, not an IP address integerคุณไม่สามารถเพียงแค่แยกสตริง IP บน".", mapฟังก์ชั่นสตริงกับจำนวน Haskell กว่าสตริงแยกและสรุปผลหรือไม่
แมว

2

ลัวะ 169 162 160 153 151 148 138 129 ไบต์

รุ่น golfed

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

มันต้องติดตั้ง Luasocket และล่ามที่รองรับป้ายกำกับ ฉันได้ทำการทดสอบกับ Luajit แล้วและฉันยังสามารถยืนยันได้ว่ารหัสนั้นไม่สามารถใช้กับ Lua 5.1 ได้

เวอร์ชันที่ไม่ดี

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

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

c:close()
goto l

แก้ไข 1:

เปลี่ยนi=({c:getpeername()})[1]เป็นเพียงแค่i=c:getpeername()

แก้ไข 2:

ลบวงเล็บปีกกาออกจากคำสั่ง require

แก้ไข 3:

ลบวงเล็บปีกการอบ vararg ลดไบต์นับเล็กน้อย

แก้ไข 4:

ลบวงเล็บที่อยู่รอบ "% d +" ซึ่งสั้นกว่า 2 ไบต์

แก้ไข 5:

ลบตัวแปรที่ไม่จำเป็นออก

แก้ไข 6:

เปลี่ยน IP จาก "127.0.0.1" เป็น 0 (ขอบคุณ xyzzy ใน #lua)

แก้ไข 7:

ลบฟังก์ชั่นการโทรไปที่ tonumber เนื่องจากสตริงถูกส่งไปยังหมายเลขโดยอัตโนมัติ (ขอบคุณ Trebuchette สำหรับคำแนะนำฉันไม่ทราบสิ่งนี้)


1
เฉพาะ Lua 5.2 และสูงกว่าป้ายกำกับการสนับสนุนหากคุณสงสัย
Trebuchette

1
นอกจากนี้ Lua จะโยนสตริงไปยังหมายเลขโดยอัตโนมัติด้วยตัว+ดำเนินการเพื่อให้คุณสามารถนำออกมาtonumberได้
Trebuchette

2

Haskell, 185 (+ 19 = 204)? ไบต์

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

ใช้หมายเลขพอร์ตเป็นหนึ่งบรรทัดบน stdin; ต้องการnetwork-simpleจากพันธมิตร

ตามปกติด้วยคำตอบของ Haskell ที่ไม่ได้ จำกัด ตัวเองให้ทำหน้าที่บริสุทธิ์ importsรับไบต์จำนวนมากเกินไป บรรทัดใหม่ต่อท้ายมีค่า 9 ไบต์ ...

ค่อนข้างคล้ายกับคำตอบของ @ Jules แต่ฉันใช้การจัดการสตริงแทนการดำเนินการไบต์ ฉันขโมยใช้-XOverloadedStringsส่วนขยายด้วยเช่นกันซึ่งอาจมีค่าเกิน 19 ไบต์


2

C, 243 188 ไบต์ (หรืออาจจะ217 162 ไบต์)

V2: ดูคำอธิบายด้านล่าง

188 ไบต์:

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

รอบคอบเล็กน้อย 162 ไบต์:

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

อาจเป็นไปได้ที่จะเล่นกอล์ฟในเช้าวันพรุ่งนี้มากขึ้น ฉันจะจัดเก็บโพสต์นี้หลังจากการอัปเดตเหล่านั้น


V1:

อันนี้สนุกมากกับการเล่นกอล์ฟ

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

มันใช้งานได้กับ IPv4 ส่วนใหญ่เป็นการใช้งานที่ไม่ซับซ้อน สามองค์ประกอบหลักคือ

การสร้างซ็อกเก็ต:

struct sockaddr_in S = {2, htons (atoi (v [1]))}, C; bind (s = ซ็อกเก็ต (2,1,0), & S, g = 16);

เราใช้รูปแบบต่าง ๆ ที่ชัดเจนของค่าคงที่ AF_INET ฯลฯ และใช้ความจริงที่ว่าเมื่อโครงสร้างเริ่มต้นใน C ด้วยวิธีนี้องค์ประกอบที่ไม่ได้ระบุจะถูกตั้งค่าเป็นศูนย์

รับฟังลูกค้ายอมรับและปิดการเชื่อมต่อ:

สำหรับ (ฟัง (s, 8); c = ยอมรับ (s & C, & g); q = fclose (g))

ในที่สุดก็ส่งข้อมูลลูกค้าแต่ละ:

สำหรับ (g = 4; กรัม; Q + = C.sin_addr.s_addr >> 8 * - G & 255); fprintf (g = fdopen (c, "W"), "% d \ n", Q);

IP ถูกเก็บC.sin_addr.s_addrเป็นจำนวนเต็ม 32 บิตโดยที่แต่ละอ็อกเท็ตถูกแทนด้วยหนึ่งในสี่ไบต์ เรารวมไบต์เหล่านี้ด้วย for for วนรอบแล้วพิมพ์ไปยังสตรีมโดยใช้ fprintf

ฉันมีวิธีแก้ปัญหาที่สั้นกว่า 217 ไบต์ แต่ฉันไม่แน่ใจว่าจะไม่ละเมิดช่องโหว่มาตรฐานเนื่องจากต้องการให้พอร์ตนั้นไม่ได้รับการรวมในลำดับไบต์ของเครือข่ายเป็นอาร์กิวเมนต์บรรทัดคำสั่ง นั่นคือการเรียกใช้เซิร์ฟเวอร์บนพอร์ต 12345 หนึ่งจะต้องโทร

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

เมื่อจำนวนรวมของ1s เท่ากับ 14640 การที่จะบอกว่าอย่างน้อยมันก็น้อย ... ยุ่งยาก แต่ที่นี่มันคือ:

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

2

แร็กเก็ต, 265 ไบต์

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

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

ตัวคูณ, 155 146 131 206 190 ไบต์

ฉันเพิ่งเรียนรู้มากมายเกี่ยวกับการเขียนโปรแกรมซ็อกเก็ตระดับต่ำ ฉันไม่คิดว่าฉันเคยต้องการที่จะทำเช่นนั้นได้อีกครั้งเพราะฉันTHRหัวเจ็บ

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

โอ้ใช่เกลียวและไม่กลับมาใช่ไหม


คุณสามารถใช้10 base>แทนได้string>numberหรือไม่?
fede s

@fedes ว้าวฉันไม่เคยรู้ว่ามีอยู่จริง ฉันคิดว่ามันจะทำให้ฉันสั้นลงหลายคำตอบของ Factor ของฉัน!
แมว

และ10 >baseสำหรับตัวเลข> สตริงด้วย
fede s

1
@fedes ผู้ที่สมควรได้รับคำตอบที่นี่ : D
cat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.