Một máy chủ TCP đơn giản


104

Viết chương trình hoặc chức năng lắng nghe lưu lượng TCP đến trên cổng N. Nó cung cấp một dịch vụ đơn giản: nó tính toán tổng các trường địa chỉ IP của kết nối đến và trả về.

Chương trình hoặc hàm đọc số nguyên N từ các đối số hoặc stdin. Nó lắng nghe các kết nối TCP đến trên cổng N. Khi ai đó kết nối với cổng đó, chương trình sẽ tính tổng các trường địa chỉ IP của nó và gửi lại cho máy khách với dòng mới và đóng kết nối.

  • Số cổng N là một cổng hợp lệ và 2 10 <N <2 15
  • Trailing newline có thể là \nhoặc\r\n
  • Bạn có thể sử dụng IPv4 hoặc IPv6. Vì các địa chỉ IPv6 được viết ở dạng thập lục phân, ví dụ, bạn cũng phải cung cấp kết quả ở định dạng tương tự 2001:0db8:0000:0042:0000:8a2e:0370:7334 => 12ecd.

Đây là . Quy tắc tiêu chuẩn và sơ hở áp dụng.

Thí dụ

Bạn chạy máy chủ của bạn với ./server 1234. Máy chủ hiện đang chạy và chờ kết nối trên cổng 1234. Sau đó, một máy khách 127.0.0.1kết nối với máy chủ của bạn. Máy chủ của bạn thực hiện một phép tính đơn giản: 127+0+0+1 => 128và gửi kết quả đến máy khách (với dòng mới theo dõi) : 128\n. Sau đó, máy chủ đóng kết nối và chờ khách hàng tiếp theo.

Bảng xếp hạng

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
Được phép sử dụng inetd / xinetd hoặc tương tự?
Chấn thương kỹ thuật số

91
Tôi thích điều này, vì đây là một thử thách chơi gôn mà ngôn ngữ chơi golf khó có thể thành thạo.
isaacg

9
Không chỉ đáng ngạc nhiên khi một máy chủ TCP rõ ràng là một chương trình rất dễ viết, tôi hoàn toàn tin tưởng vào thực tế rằng nó đang được chơi golf để giải trí. Tôi sẽ quay trở lại đấu tranh với FizzBuzz như một kẻ ngu ngốc.
MonkeyZeus

17
@isaacg Đó là chỉ thời gian trước khi ai đó tìm thấy máy chủ TCP tích hợp sẵn trong Mathematica
Downgoat

3
@MonkeyZeus Để công bằng, bạn sẽ không thấy bất kỳ máy chủ TCP tốt nào ở đây. Tạo một máy chủ TCP đáng tin cậy, có thể mở rộng để xử lý tất cả các vấn đề phức tạp của TCP (và giao thức ứng dụng của bạn) khó hơn một chút: D Mặc dù điều đó chắc chắn giúp giao thức cực kỳ đơn giản - bạn thậm chí không cần phải đọc luồng, một cái gì đó mà tôi đã thấy bị hỏng trong quá nhiều máy chủ TCP để đếm: D
Luaan 30/03/2016

Câu trả lời:


57

Bash + netcat + ss + Hoài, 65 60 ký tự

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

Không phải là một giải pháp nghiêm túc, chỉ tò mò về khả năng này.

Nhờ vào:

  • ninjalj để đề xuất awkbộ lọc dựa trên (-5 ký tự)

Chạy mẫu:

(thiết bị đầu cuối 1)

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

(thiết bị đầu cuối 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.

Trên Ubuntu, bạn có thể lấy nctừ netcat-truyền thống (không, netcat-openbsd không tốt) và sstừ iproute2 .


22
Tại sao bạn nói nó không phải là một giải pháp nghiêm trọng? Miễn là nó hoạt động như mong đợi, tôi thấy không có lý do gì mà nó không được coi là nghiêm trọng. Nó cũng là ngắn nhất bởi một lề khá đáng kể tại thời điểm này.
Alex A.

Mối quan tâm lớn nhất chống lại nó xuất hiện trong cuộc thảo luận với @JesseSielaff khi tôi biết rằng trên các hệ thống có cấu hình IPv6, thông tin liên quan đến ổ cắm có thể được định dạng khác nhau. Không có hệ thống như vậy để kiểm tra nó. Mà tôi đang suy nghĩ liệu có đúng hơn không khi biến nó thành CW.
manatwork 28/03/2016

3
Sự hiểu biết của tôi về thông số kỹ thuật là bạn phải hỗ trợ IPv4 hoặc IPv6 chứ không phải cả hai. Vì vậy, miễn là nó hoạt động cho IPv4, không hỗ trợ IPv6 thì không thành vấn đề, tôi nghĩ vậy.
Alex A.

1
@AlexA. Ít nhất tôi nghĩ rằng câu hỏi của tôi nói như vậy. Tôi có nên làm rõ nó?
Hannes Karppila

@HannesKarppila, câu hỏi của bạn rất rõ ràng. Vấn đề có thể là giải pháp của tôi có thể yêu cầu hệ điều hành phải được cấu hình theo một cách cụ thể để có thể chạy. Vì vậy, tôi lo lắng vì nó có thể thất bại nếu IPv6 được cấu hình, bất kể tôi có xử lý hay không. Ai đó đã cấu hình IPv6 có thể nói với nó chắc chắn rằng
manatwork

23

C #, 284 283 282 278 274 254 byte

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

Ví dụ cổ điển về máy chủ C # TCP cơ bản. Kiểm tra:

Nhà ga 1:

$ ./Q76379.exe 1029

Nhà ga 2:

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

Firefox:


7
Bạn có thể tiết kiệm 1 Byte bằng cách sử dụng int Mainthay vì void Main. Vì chương trình không bao giờ trả về trình biên dịch nên không yêu cầu một returncâu lệnh.
raznagul

Và không, nó không bị rò rỉ. Nó thực sự khá quyết định về việc phát hành tài nguyên là tốt. Ngoài ra, đối số Startlà tùy chọn, lưu một ký tự khác.
Luaan 30/03/2016

@Luaan Vâng, đó là phần còn lại từ gỡ lỗi.
LegionMammal978 30/03/2016

Ngoài ra, bạn có thể sử dụng usingtrên TcpClient, điều này sẽ giúp bạn tiết kiệm thêm ba ký tự (sử dụng {}từ for) và thực hiện tương tự với việc StreamWriterlưu thêm một ký tự.
Luaan 30/03/2016

@Luaan tôi cần phải rõ ràng Flushsự StreamWriterđể làm cho nó hoạt động đúng.
LegionMammal978 30/03/2016

22

Linux ELF / x86, 146 byte

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

Bao gồm tiêu đề ELF 52 byte, tiêu đề chương trình 32 byte, 111 byte mã chương trình + 3 byte mã để bỏ qua bên trong các tiêu đề.

Thông tin về làm thế nào để tạo ra thực thi ELF nhỏ có thể được tìm thấy tại breadbox 's ' Một Whirlwind Hướng dẫn về Tạo Thật teensy ELF Executables cho Linux ' .

Linux / i386 sử dụng socketcall(2)lệnh gọi hệ thống ghép kênh, thực hiện ebxcuộc gọi ổ cắm cụ thể ( SYS_*macro từ /usr/include/linux/net.h) và trong ecxmột con trỏ tới vùng đối số của lệnh gọi thư viện gốc.

Một số điều được thực hiện để giữ cho thực thi nhỏ:

  • Nó giả sử các thanh ghi bằng 0 khi nhập, mà Linux thực hiện, nhưng không bắt buộc theo tiêu chuẩn ELF (yêu cầu duy nhất là trên EDXcác điểm nhập vào một chức năng hoàn thiện (hữu ích cho các tệp thực thi được tải bởi trình liên kết động) hoặc là NULL).
  • Nó giả định khi khởi chạy (thường là bằng vỏ), các mô tả tệp mở duy nhất là 0, 1 và 2. Điều đó có nghĩa là ổ cắm nghe sẽ là fd 3 và ổ cắm được chấp nhận sẽ là fd 4.
  • Nó giả sử có chính xác 2 đối số (bao gồm argv[0]).
  • Không gian ngăn xếp cùng được tái sử dụng cho các cuộc gọi đến bind(2), listen(2)accept(2).
  • Để bỏ qua các trường phentsizephnumcác trường, một byte được chuẩn bị trước, biến thành một CMPhoạt động lấy các trường phentsizephnumngay lập tức (lừa bị đánh cắp một cách đáng xấu hổ từ giải pháp của Breadbox đến 123 trong golf vô chính phủ ).
  • Các hoạt động chuỗi x86 LODS(tải vào bộ tích lũy và chỉ số nguồn tăng / giảm) và STOS(lưu trữ từ bộ tích lũy và chỉ số đích tăng / giảm) là tốt cho mã ngắn.
  • XCHG EAX, reglà 1 byte, so với MOV EAX, reg, mất 2 byte.
  • CDQ/CLTD(đăng nhập mở rộng EAXvào EDX:EAX) có thể được sử dụng như một cách 1 byte để không EDXđăng ký.
  • BSWAPlà hữu ích để thực hiện htons().

Nguồn liên kết:

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
Câu trả lời này là cách đánh giá thấp.
con mèo

16

NodeJS, 146 134 127 byte

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

Cuối cùng tôi cũng nhận được một câu trả lời NodeJS! Chỉ có IPv4 ngay bây giờ.

Thực hiện mẫu : node script.js 1024. Từ một thiết bị đầu cuối khác:

$ curl 127.0.0.1:1024
128

2
Tôi đếm 127 byte ngay bây giờ, mặc dù bạn có thể giảm xuống còn 126 bằng cách hoán đổi '\n'với một chuỗi mẫu có chứa một dòng mới.
Mwr247

Điều này có làm thất bại các yêu cầu không vì ý nghĩa của bạn là tạo máy chủ HTTP, về mặt kỹ thuật, đó là máy chủ TCP, nhưng bạn không thể sử dụng mô-đun TCP và tự lưu lại một ký tự?
MayorMonty

14

Tcl, 92

  • Lưu 1 byte nhờ @DonalFellows.
proc s {c a p} {puts $c [expr [string map .\ + $a]]
close $c}
socket -server s $argv
vwait f

Khá tự giải thích:

socket -server s $argv tạo ra một ổ cắm nghe trên cổng được chỉ định trong các đối số.

Mỗi khi có kết nối mới, proc ssẽ được gọi, với kênh, địa chỉ nguồn và cổng nguồn làm tham số. string mapthay thế .cho +trong địa chỉ nguồn và exprđánh giá một cách hợp lý kết quả, sau đó putsquay lại kênh kết nối c.

vwait chạy một vòng lặp sự kiện để bắt các sự kiện kết nối đến.


Tín dụng cho @DonalFellows cho các mục sau:

Đây là phiên bản xử lý IPv6 (yêu cầu Tcl 8.6; hầu hết độ dài thêm là do tạo ra phản hồi hex):

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
Sử dụng applydường như không tiết kiệm bất cứ điều gì. Bạn cũng không thể sử dụng tcl::mathop::+ {*}[split $a .]vì nó hơi dài. Bạn cũng không thể cạo bất cứ thứ gì từ tên tùy chọn. Nhưng việc hỗ trợ IPv6 khá đơn giản để thêm vào và chỉ tốn thêm một vài byte mã (và sau đó, regsubcách tiếp cận dựa trên cơ sở cũng dài như vậy).
Donal Fellows

ahhh, Tcl / Tcl-DP ... một loạt các công cụ tuyệt vời. (trong thập niên 90, một giáo sư đã cho chúng tôi thấy chúng tôi có thể viết một Excel phân phối mạng (với một lưới và bao gồm cả đánh giá công thức!) được chia sẻ giữa một số người với (iirc) 4 (ngắn) cho máy chủ và 5 cho các máy khách. ..
Olivier Dulac

proc s {c a p}Bạn có thực sự cần tất cả khoảng trắng đó?
con mèo

12

Groovy 133 , 125 , 93 , 89

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

Chỉ có thể có IPv4.

Ung dung:

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

Kiểm tra:

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

1
.toInteger()as ints.inetAddress.address*.toInteger()(s.inetAddress.address as int[]). Và có một không gian thêm sau .with.
manatwork 28/03/2016

@manatwork thx! Đã cập nhật.
Will Lp

9

Python 3, 170 166 147 byte

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

Đưa cổng vào stdin, chỉ IPv4. Hoạt động trên GNU / Linux (và, tôi giả sử, hầu hết các hợp nhất khác), tự động mở rộng "" thành "0.0.0.0", mặc dù không chắc chắn về Windows.


2
Bạn có thể lưu một vài byte. Thứ nhất, không gian trong import *, SOCK_STREAMkhông cần thiết. Ngoài ra, dòng gửi có thể được viết hiệu quả hơn như c.send(b"%d\n"%eval(a[0].replace(".","+"))).
Hannes Karppila

2
@HannesKarppila oh, cảm ơn. Quên về không gian, hack eval là khá mát mẻ mặc dù.
sammko

2
AF_INET và SOCK_STREAM chỉ là hằng số; AF_INET là 2 và SOCK_STREAM là 1. Ngoài ra, như đã đề cập, SOCK_STREAM là không cần thiết; vì vậy bạn có thể rút ngắn điều đó bằng cách sử dụng s=socket(2).
Skyler

1
bạn không thể làm socket () và do đó lưu một byte khác?
Foon

1
Bạn có thể lưu 10 ký tự bằng cách sử dụng Python 2. Sau đó, int(input())trở thành input()và phần gửi trở thànhc.send(`eval(a[0].replace(".","+"))`)
Blender

9

Java, 371 368 350 344 333 310 295 282 byte

Chơi gôn

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

Bị đánh cắp

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

Đầu ra

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

1
Loại bỏ int k=và thay thế k với tất cả những điều c trong Integer.toString(k). Để tiết kiệm một vài byte.
GiantTree

1
Javas byte khá chắc chắn làm rối giá trị trả về cho 192.168.2.1 hoặc các địa chỉ tương tự có byte trên 127.
AlexR

1
Thay đổi interfacethành classsẽ nhận được thêm vài byte
ortis

2
Sử dụng a.getOutputStream().write((c[0] + c[1] + c[2] + c[3]+"\n").getBytes());thay vìnew DataOutputStream(a.getOutputStream()).writeBytes(c[0] + c[1] + c[2] + c[3] + "\n")
ortis

3
Không try(Socket a=...){}ngắn hơn a.close();? Yêu cầu Java 7, nhưng có thể thu được byte.
Olivier Grégoire

8

PowerShell v2 +, 303 268 257 227 byte

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

Đã lưu 35 byte nhờ Matt ... Đã lưu thêm 11 byte bằng cách đặt bí danh New-Objectvà các chỉnh sửa nhỏ ... Đã lưu thêm 30 byte bằng cách sử dụng localhost thay vì anyđịa chỉ IP và sửa thành tài khoản để sử dụng liên tục như đã chỉ định ban đầu và tôi đã bỏ lỡ

Thực sự giống với câu trả lời C # , vì .NET nằm dưới cả hai. Chúng tôi lưu một vài byte ở đây qua câu trả lời C # bằng cách có thể tận dụng chức năng trả về của PowerShell (xung quanh khai báo / gán của chúng tôi trong parens, và sau đó gọi ngay các phương thức.), Nhưng chúng tôi mất rất nhiều bằng cách cần thiết lập tổng kết . Thực tế là chúng tôi đã có các tên lớp / cuộc gọi ngắn hơn một chút thực sự là lý do tại sao câu trả lời này đang đánh bại C #.

Giải trình

Trước tiên chúng ta tạo một New-Alias(với nalbí danh) để lưu lại khi gõ lại New-Objectsau. Phần còn lại của dòng đầu tiên là thiết lập Trình nghe TCP. Chúng tôi chuyển dòng lệnh $args[0]làm đầu vào để tạo mới System.Net.Sockets.TcpListener, được lưu trữ dưới dạng $l. Đối tượng đó được gói gọn trong parens và ngay lập tức được gọi .Start()để có nó chủ động mở ổ cắm.

Bước vào một forvòng lặp vô hạn , sau đó chúng tôi đặt trình nghe của $lmình thành chặn AcceptTcpClient()để chờ kết nối. Một tham chiếu đến kết nối đó (một khi nó được thực hiện) được lưu trữ $c, được gói gọn trong parens và ngay lập tức được gọi GetStream()để lấy dữ liệu. Kho dữ liệu đó được truyền cho một nhà System.IO.StreamWriterxây dựng mới $w, vì vậy chúng ta có thể thao tác nó. Hàm tạo đó tự nó được gói gọn trong parens và được gọi ngay lập tức Write(...).

Trong Write(...)cuộc gọi, chúng tôi xử lý khách hàng của chúng tôi $cvà có được RemoteEndPointtài sản của khách hàng . Đây là cách duy nhất (mà tôi đã tìm thấy cho đến nay) để có được địa chỉ IP từ xa. Tiếp theo, chúng ta cần truyền lại nó dưới dạng một [System.Net.IPEndPoint]đối tượng để nó được định dạng chính xác, đóng gói nó trong parens và chỉ lấy thuộc .Addresstính. Chúng tôi sau đó -replacecác giai đoạn theo nghĩa đen với dấu cộng, sau đó chuyển nó sang Invoke-Expression(tương tự eval) để có được tổng kết của chúng tôi.

Sau khi viết IO, chúng ta cần gọi .Dispose()để đảm bảo luồng dữ liệu được tuôn ra cho máy khách và đóng lại. Máy chủ TCP ngắt kết nối máy khách mà không có cảnh báo, do đó tùy thuộc vào máy khách được sử dụng, nó có thể bị treo trong một thời gian tại thời điểm này. Sau đó nó tiếp tục qua forvòng lặp mà không đóng các kết nối đúng cách. Điều này cũng có nghĩa là nó rò rỉ bộ nhớ và hệ thống xử lý như điên, nhưng chúng ta không quan tâm đến điều đó, phải không? Tuy nhiên, bạn có thể cần phải sử dụng Trình quản lý tác vụ để hủy quá trình khi bạn chạy xong máy chủ. :CƯỜI MỞ MIỆNG

Ngoài ra, chỉ có IPv4, khi các bảng tóm tắt cố gắng xử lý một địa chỉ IPv6 một cách ngoạn mục, vì :không phải là toán tử đại số hợp lệ iexđể phân tích cú pháp.


2
"Rò rỉ bộ nhớ và hệ thống xử lý như điên" Cái gì, bạn có để free()chúng sau không? delete[], có lẽ? : P
mèo

8
@tac Vâng, có cả một loạt các phương thức .close().dispose()chúng tôi không gọi ở đây sẽ khiến mọi người trên Code Review có sự phù hợp.
admBorkBork 28/03/2016

Ồ, không phải PS GC'd sao? Hay là GC thực hiện đếm và không phân tích phạm vi?
mèo

@tac Có, PowerShell có bộ sưu tập rác nhờ hệ thống .NET cơ bản. Nhưng, tùy thuộc vào cách bạn đang gọi điện thoại hoặc tận dụng kịch bản này, bạn có thể chạy vào các lỗi như này bị rò rỉ bộ nhớ trong các đường ống. Đoạn mã trên cũng không an toàn cho luồng và do đó có thể gặp phải các vấn đề về GC, vì chúng tôi không đóng ổ cắm một cách rõ ràng.
AdmBorkBork

1
Trong thử nghiệm, tôi không thể làm việc này, có thể do sự cố tường lửa mà tôi không muốn sửa nên tôi không chắc nhưng ..... Tôi nghĩ bạn có thể bỏ "Hệ thống" khỏi hầu hết nếu không phải tất cả các kiểu phôi bạn có đó tức là: [Net.ipaddress]::Anycông trình.
Matt

7

PHP, 161 (56?)

Đây là bài viết đầu tiên của tôi ở đây. Tôi hy vọng điều này đi đúng :)

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

Ung dung:

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

Thiết bị đầu cuối:

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

Điều này chỉ hoạt động cho IPV4

Chỉnh sửa : Tôi chỉ nhận thấy rằng php hỗ trợ máy chủ cơ bản:
Tôi đã quyết định bám vào số ký tự gốc trừ khi có ai đó xác nhận nếu cho phép sau :)

test2.php: (giải pháp 56 byte có thể)

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

Và sau đó bắt đầu dịch vụ với:

php -S localhost:8080 test2.php

Chrome là khách hàng ảnh chụp màn hình

Chỉnh sửa 2: wget là khách hàng

$ wget -qO- localhost:8080
128

Tôi biết các quy tắc nói: "Chương trình hoặc hàm đọc số nguyên N từ các đối số hoặc stdin", nhưng liệu có ổn không nếu chương trình trong trường hợp này là chính php? Hoặc là sử dụng máy chủ dựng sẵn trong php được coi là kẽ hở?
Mikael

Chào mừng bạn đến với Câu đố lập trình & Code Golf! Giải pháp 161 byte của bạn trông tuyệt vời. Là giải pháp 56 byte mà bạn đã đề cập dưới đây test2.php? Nếu vậy, tôi nghĩ rằng bạn phải hỏi OP xem họ có xem loại tích hợp đó có thể chấp nhận được cho thử thách này không. Nó không phải là một lỗ hổng mặc dù.
Alex A.

Tôi có thể nói, sử dụng máy chủ TCP dựng sẵn sẽ được chấp nhận, nhưng trong trường hợp này chúng ta nói về máy chủ HTTP dựng sẵn . Vì vậy, giải pháp 56 byte 1) không làm gì nếu máy khách chỉ kết nối và không gửi gì; 2) chỉ gửi lại chỉ [Thứ ba ngày 30 tháng 3 10:15:02 2016] 127.0.0.1:47974 Yêu cầu không hợp lệ (Yêu cầu HTTP không đúng định dạng) mà không chạy test2.php trong trường hợp khách hàng gửi ví dụ như foo f; 3) gửi toàn bộ tiêu đề phản hồi HTTP trước khi phản hồi được yêu cầu thực tế trong trường hợp máy khách gửi yêu cầu HTTP hợp lệ.
manatwork 30/03/2016

@Alex A. Cảm ơn bạn và vâng, giải pháp 56 byte nằm dưới test2.php :)
Mikael

@manatwork Bạn đúng nhưng tôi đã nghĩ rằng khách hàng không được chỉ định rõ ràng trong nhiệm vụ này. Vì vậy, có ổn không khi sử dụng trình duyệt hoặc thậm chí đơn giản hơn một cái gì đó như "wget ​​-qO- localhost: 8080" làm máy khách?
Mikael

7

Đi , 359 311

Đây là chương trình đầu tiên của tôi trong Go - Nó cho phép tôi khám phá một điều: Đây chắc chắn không phải là một ngôn ngữ chơi golf tốt!

(Kudos gửi tới @steve, người đã chơi golf nhiều nhất!)

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
Nhưng nó chắc chắn là một ngôn ngữ tốt để tạo một máy chủ tcp!
numeri

1
Kì lạ, tôi nhận được kết quả 360 khi tôi kết nối từ 192.168.0.67, thay vì 427.
steve

3
Bạn có thể đặt tên cho các gói chuỗi + strconv để lưu một vài byte. ví dụ như "strings"trở thành s "strings"để sau này strings.Splitchỉ trở nên s.Split.
steve

1
Ít byte hơn đã bị loại bỏ pastebin.com/HY84sazE - bắt đầu trông hơi "chơi gôn" hơn bây giờ
steve

2
Nếu bạn sử dụng import(."pkgname")tất cả các hàm sẽ được nhập vào không gian tên hiện tại, thì bạn có thể bỏ tiền tố. ví dụ. import ."fmt"; Println("foo") Nếu bạn sử dụng Sscanftừ fmtgói để phân tích địa chỉ thay vì regex, nó sẽ giúp bạn tiết kiệm thêm một vài byte, mang lại cho bạn phần thưởng tuyệt vời khi Fprintlntrả lại tổng số thay vì nhập strconv.
Kristoffer Sall-Storgaard

7

Lisp thông thường, 110 byte

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

Chi tiết

(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 cho tiếng Litva thông thường!
con mèo

6

q, 88 byte

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: Đưa đối số dòng lệnh thứ hai (đầu tiên "-"là để nói qkhông diễn giải Ndưới dạng tập lệnh / tệp) và mở một cổng ( "p ") với nó.
    • Lưu ý: Việc gọi q -p Nđặt cổng là Ntự động, nhưng vì câu hỏi dường như gợi ý rằng đó Nnên là một đối số cho chương trình thay vì bản thân thực thi, tôi đã đi một chặng đường dài hơn.
  • Bên trong .z.pghàm xử lý các yêu cầu đến, .z.agiữ địa chỉ IP dưới dạng số nguyên 32 bit.
    • "i"$0x0 vschia nó thành số nguyên 'thành phần' của nó và sumthực hiện phép tính tổng.
    • Cuối cùng, stringkết quả số và nối "\n"vào nó để trả về máy khách.
  • .z.ph là một chức năng khác cho các yêu cầu HTTP GET, với việc xử lý bổ sung để chuyển đổi đầu ra chuỗi thành phản hồi HTTP hợp lệ.

Bản trình diễn - Máy chủ:

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áy khách (từ qphiên khác đang chạy 127.0.0.1):

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

Demo - Khách hàng (từ curl):

$ curl localhost:1234
128

$

6

LiveScript, 107 105 byte

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

Không có gì nhiều để thêm, đó chỉ là công cụ NodeJS cơ bản. Điểm phong cách cho &1(đối số thứ hai), <|(F # piping, gần giống với $Haskell) và biop: (+)trong LS giống như các phần toán tử trong Haskell: một hàm nhị phân được thêm vào (có thêm toán hạng của nó). Cũng là một chút bẩn: /, nếu có một literal chuỗi bên phải của nó, sẽ làm chia rẽ.


5

Perl, 141 132 + 1 = 133 byte

Chơi gôn

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

Bị đánh cắp

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

Thí dụ

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

Bạn có chắc chắn điều này là chính xác? Tôi nhận được số tiền được in trong thiết bị đầu cuối của máy chủ, không phải của khách hàng. Dù sao, bạn có thể loại bỏ tất cả dấu ngoặc đơn và thay đổi s/\./+/gy/./+/.
manatwork 28/03/2016

Ahh, đọc sai..sẽ sửa lại cho phù hợp và kết hợp y / đề nghị tốt của bạn.
steve

1
while(1){…}{…;redo}theo mẹo tuyệt vời của user130144 . Và ngoại trừ cuộc gọi, tất cả các dấu ngoặc đơn khác là không cần thiết. ->send()
manatwork

4

Python 2, 180 byte

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

Đưa cổng qua stdin.


4

NodeJS (ES6), 129 118 107 byte

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

Hoạt động cho IPv4. Chạy nhưnode server.js <port>


Trên thực tế không hoạt động nếu máy chủ sử dụng IPv6 (ví dụ như của tôi tự động), kể từ c.remoteAddressđó sẽ như vậy ::ffff:127.0.0.1. (Tôi đã thử nghiệm trên Node v5.9.1).
Frxstrem

Ngoài ra, bạn không có một dòng mới, điều này sẽ làm tăng điểm của bạn thêm 2 byte.
Frxstrem

@Frxstrem Rất tiếc, quên dòng mới đó. Chỉ thêm 1 byte mặc dù nhờ các chuỗi mẫu. Về họ IP: .listen()trước tiên được sử dụng để mặc định cho IPv4, nhưng dường như do lỗi hoặc thiết kế mà điều này đã thay đổi. Việc gửi vẫn sẽ hoạt động đúng trên các phiên bản nút mới hơn khi IPv6 bị vô hiệu hóa trên máy chủ.
Mwr247

4

Đi, 211 byte

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

Có lẽ có thể chơi gôn hơn nữa, tôi không hoàn toàn hài lòng với cách tôi phải phân tích địa chỉ IP chẳng hạn, nó trông giống như một vụ hack khủng khiếp.

Nghe trên IPv4 trên cổng được đưa ra làm đối số.


4

PowerShell, 208 206 192 152 byte

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

thông tin phiên bản:

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

Cảm ơn TimmyD đã tiết kiệm cho tôi 14 byte!

Rất cảm ơn TessellatingHeckler đã tiết kiệm cho tôi 40 byte


@TimmyD ah oops Tôi đã bỏ lỡ điều đó là cần thiết ... đã được sửa ngay bây giờ
Nacht

Một trong những cách chương trình được phép lấy đầu vào là từ stdin. Tôi cho rằng câu hỏi cụ thể này không chỉ định rằng như được cho phép nhưng đó là một điều chung về môn đánh gôn mà tôi nghĩ nên tính cho PowerShell. Thật không may, khác với bash ở chỗ nó không đợi đầu vào trên stdin nếu không được cung cấp.
thuyền

đủ công bằng. cố định lại
Nacht

Được rồi, bây giờ đối với một số golf - hãy thử như sau tại 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
Tôi nghĩ rằng bạn có thể hạ nó xuống 152 - thả đối tượng mới và truyền trực tiếp, bỏ qua chuyển đổi mảng byte và thực hiện một chuỗi khác nhau, không lưu trữ $ x chút nào và bỏ các tham số còn lại để gửi () và nó trở thành ($t=[net.sockets.tcplistener]$args[0]).start();for(){($z=$t.acceptsocket()).send([char[]]"$($z.remoteendpoint.address-replace"\.","+"|iex)");$z.close()}- điều mà tôi chỉ thử nghiệm nhanh chóng với kết nối netcat, nhưng dường như nó cũng hoạt động tương tự - kết nối từ localhost.
TessellatingHeckler

4

Mã máy 8086 (DOS 16 bit), 163 156 148 148 142 byte

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

Mã lắp ráp tương đương:

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

Giả định ntcpdrvnày được tải tại INT 0x61(và bất kỳ trình điều khiển gói phù hợp nào tại 0x60). Biên dịch với fasm tcpserv.asm.

Nó có một số vấn đề mặc dù:

  • Nó không kiểm tra xem đối số có phải là số cổng hợp lệ hay không, hoặc thậm chí đó có phải là số không.
  • Máy khách phải gửi ít nhất một byte, vì dường như tôi không thể tìm thấy bất kỳ cách nào khác để biết khách hàng có kết nối hay không.
  • Nó chỉ hoạt động một lần, và cố gắng lần thứ hai. Hoạt động trở lại sau khi khởi động lại.
  • Giá trị trả về được đệm trái với số không.
  • Đây là lần đầu tiên chơi golf mã, và cũng là chương trình 8086 asm đầu tiên của tôi. Tôi chắc chắn có nhiều cách để cải thiện điều này hơn nữa.

1
Bạn chỉ có thể đăng một hexdump của đầu ra được biên dịch cho 148 byte
cat

Điều đó có được phép không? Nó sẽ làm cho mục này cạnh tranh hơn một chút ...
user5434231

1
Được rồi, tôi đã thay đổi mục nhập thành mã máy. Cũng cạo thêm một vài byte bằng cách sử dụng xor r,rthay vì mov r,0.
dùng5434231

1
Tôi đã viết nó trên một máy dos nơi có dòng mới CR LF, vì vậy tôi chỉ đi với nó. Dù bằng cách nào thì việc đếm kích thước asm bây giờ cũng vô nghĩa, cũng có thể làm sạch nó một chút và thêm một số nhận xét.
dùng5434231

1
Điều đó cũng xảy ra ở đây, và nó hoạt động; int 0x61trả về một cổng cục bộ ngẫu nhiên trong ax. Nhưng nó cũng thay đổi IP nghe thành một số số rác ( 4.2.0.0iirc)
user5434231

3

Haskell, 216 byte

Sử dụng gói "mạng đơn giản" ( cabal install network-simple). Cần một vài phần mở rộng ngôn ngữ ( -XOverloadedStrings -XNoMonomorphismRestriction) để hoạt động.

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)

Có một số đơn giản hóa có thể, bao gồm thay đổi whàm để trả về tổng trực tiếp thay vì danh sách và sử dụng hàm thay vì chương trình để số cổng có thể được chỉ định làm đối số. Tôi không tưởng tượng điều này sẽ làm giảm kích thước rất nhiều, mặc dù. 20 byte có lẽ?


Đẹp! Khá chắc chắn rằng bạn vẫn có thể tắt một vài byte bằng cách đổi tên wthành #, vì vậy w h nsẽ h#ntiết kiệm được 2 byte cho mỗi lần sử dụng.
Actorclavilis

3

Quai bị, 114 115 byte

Chơi gôn

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}

Ung dung:

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

Đây là phiên bản Quai của InterSystems - nếu có phiên bản ngoài đó có thể thu được địa chỉ TCP ngắn hơn ##class(%SYSTEM.TCPDevice).PeerAddr() (vì nó gần bằng 1/3 toàn bộ chương trình) thì có thể có cơ hội tốt hơn đối với một số ngôn ngữ khác đã đăng ... ;-)

Chỉnh sửa: Cảm ơn @TimmyD - Tôi đã bỏ lỡ việc đọc cổng từ STDIN hoặc các đối số thay vì bị mã hóa cứng. Đã chỉnh sửa; nó đã thêm 1 byte vào chương trình.


@TimmyD - Ah, bạn đã đúng. Bỏ lỡ điều đó khi đọc qua các yêu cầu. Sẽ chỉnh sửa hậu kỳ.
zmerch

3

C, 535 byte

Vâng, ai đó đã phải làm điều này.

Tôi đã thêm một dấu ngắt dòng để mã được đăng thực sự có 536 ký tự.

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

biên dịch với gcc [file_name] -o server

chạy với ./server [port]

kết nối với telnet localhost [port]


3
Câu trả lời tốt đẹp! Như đã đề cập trước đây , bạn có thể lưu một vài byte bằng cách sử dụng các giá trị thực tế cho một số hằng số, chẳng hạn như AF_INET và SOCK_STREAM.
Hannes Karppila

2

Java, 210 byte

Chơi gôn

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

Mở rộng:

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

Đây là một tập hợp tất cả các mẹo tôi đã đưa ra trong các câu trả lời Java khác, cộng với việc viết dưới dạng hàm thay vì một chương trình đầy đủ, thu được khoảng 70 byte so với chương trình.


2

Haskell, 326 byte

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)

Đáng buồn là tôi đã phải sử dụng Network.Socketđể có quyền truy cập vào địa chỉ IP từ xa dưới dạng một số nguyên chứ không phải là một chuỗi. Nó đã có thể lưu hàng chục nhân vật nếu tôi chỉ có thể làm được s <- listenOn (PortNumber n), thay vì phải gọi một cách rõ ràng socket, bindlistencá nhân. Nhưng, thật đáng buồn, Network.acceptcho tôi một chuỗi máy chủ , không phải là số nguyên địa chỉ IP , vì vậy tôi đã phải nhờ đến Network.Socket.acceptbạn bè.

Hàm flấy số cổng làm đối số và tạo một ổ cắm máy chủ ( s) lắng nghe trên cổng đó. Sau đó, nó gọi chức năng gvới ổ cắm máy chủ. gvòng lặp mãi mãi, chấp nhận kết nối. Hàm blấy một địa chỉ IPv4 thực tế và tính tổng các chữ số của nó.

Tôi chắc rằng ai đó ở đâu đó có thể làm điều này tốt hơn tôi. Tôi muốn chỉ ra cách thức các công cụ ổ cắm dễ bị nguyền rủa trong Haskell ... nhưng sau đó thất bại thảm hại, vì tôi cần truy cập vào địa chỉ IP, điều này thường không dễ dàng có được.


Gói "mạng đơn giản" cung cấp giao diện đẹp hơn nhiều, chuyển SockAddr đến một chức năng mà bạn cung cấp, giúp mọi việc dễ dàng hơn. Xem giải pháp của tôi mà tôi sắp đăng ...
Jules

Một vài đơn giản hóa là rõ ràng: (1) Tôi tin rằng withSocketsDochỉ cần thiết trên Windows, vì vậy nếu chạy trên Linux thì có thể bỏ qua; (2) 0xFF là ký tự dài hơn 255; (3) chuyển đổi ổ cắm sang tay cầm và sử dụng IO thông thường lâu hơn nhiều so với sử dụng Network.Socket.send. Có, sendkhông được chấp nhận, nhưng lý do không liên quan đến kịch bản này (nó chỉ liên quan đến văn bản hoặc dữ liệu nhị phân không phải ASCII), vì vậy có vẻ hợp lý khi sử dụng nó.
Jules

Network.accept gives me a host string, not an IP address integerBạn không thể phân tách chuỗi IP trên ".", hàm mapchuỗi số của Haskell trên chuỗi phân tách và tổng hợp kết quả?
con mèo

2

Lua, 169 162 160 153 151 148 138 129 byte

Phiên bản chơi gôn

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

Nó yêu cầu Luasocket phải được cài đặt và một trình thông dịch hỗ trợ nhãn. Tôi đã thử nghiệm nó với Luajit và tôi cũng có thể xác nhận rằng mã không hoạt động với Lua 5.1.

Phiên bản ung dung

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

Chỉnh sửa 1:

Thay đổi i=({c:getpeername()})[1]thành chỉi=c:getpeername()

Chỉnh sửa 2:

Loại bỏ niềng răng từ tuyên bố yêu cầu.

Chỉnh sửa 3:

Loại bỏ các dấu ngoặc xung quanh vararg, giảm số byte một chút.

Chỉnh sửa 4:

Đã xóa dấu ngoặc đơn quanh "% d +", ngắn hơn 2 byte.

Chỉnh sửa 5:

Loại bỏ các biến không cần thiết i.

Chỉnh sửa 6:

Đã thay đổi ip từ "127.0.0.1" thành 0. (Cảm ơn xyzzy trên #lua)

Chỉnh sửa 7:

Đã xóa chức năng gọi tới tonumber vì các chuỗi được tự động chuyển sang số (Nhờ Trebuchette cho đề xuất, tôi không biết điều này)


1
Chỉ Lua 5.2 trở lên nhãn hỗ trợ, nếu bạn tò mò
Trebuchette

1
Ngoài ra, Lua tự động chuyển chuỗi thành số với +toán tử, do đó bạn có thể lấy ra tonumber.
Trebuchette

2

Haskell, 185 (+ 19 = 204)? byte

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)

Lấy số cổng là một dòng trên stdin; yêu cầu network-simpletừ Cabal.

Như thường lệ với các câu trả lời của Haskell không giới hạn các hàm thuần túy, việc importschiếm quá nhiều byte. Dòng mới theo dõi cũng có giá trị 9 byte ...

Khá giống với câu trả lời của @ Jules, nhưng tôi sử dụng thao tác chuỗi thay vì thao tác byte. Tôi đã đánh cắp-XOverloadedStrings phần mở rộng cũng được sử dụng , có lẽ trị giá thêm 19 byte.


2

C, 243 188 byte (hoặc có lẽ là 217 162 byte)

V2: xem bên dưới để giải thích.

188 byte:

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

Hơi hẹp chu vi 162 byte:

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

Có lẽ nhiều golf có thể vào sáng mai. Tôi sẽ dọn dẹp bài đăng này sau những cập nhật đó.


V1:

Điều này thực sự khá thú vị để chơi gôn.

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

Nó hoạt động cho IPv4. Chủ yếu là thực hiện đơn giản. Ba thành phần chính là

Tạo ổ cắm:

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

Chúng tôi sử dụng các hình thức rõ ràng khác nhau của các hằng số AF_INET, v.v. và sử dụng thực tế là khi một cấu trúc được khởi tạo trong C theo cách này, các phần tử không được chỉ định được đặt thành không.

Lắng nghe khách hàng, chấp nhận họ và đóng kết nối của họ:

for (nghe (s, 8); c = accept (s, & C, & g); q = fc Đóng (g))

Cuối cùng để gửi cho mỗi khách hàng dữ liệu:

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

IP được lưu trữ C.sin_addr.s_addrdưới dạng số nguyên 32 bit trong đó mỗi octet được biểu thị bằng một trong bốn byte. Chúng tôi tổng hợp các byte này với vòng lặp for và sau đó in chúng ra luồng bằng fprintf.

Tôi có một giải pháp ngắn hơn 217 byte nhưng tôi không hoàn toàn chắc chắn rằng nó không vi phạm các lỗ hổng tiêu chuẩn vì nó yêu cầu rằng cổng được đưa ra một cách đơn nhất theo thứ tự byte mạng như các đối số dòng lệnh. Đó là, để chạy máy chủ trên cổng 12345, người ta sẽ cần phải gọi

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

trong đó tổng số 1s là 14640. Để nói rằng ít nhất nó hơi ... cồng kềnh. Nhưng dù sao nó ở đây:

#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

Vợt, 265 byte

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

Ung dung:

#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

Yếu tố, 155 146 131 206 190 byte

Chà, tôi mới học được rất nhiều về lập trình socket cấp thấp. Tôi không nghĩ rằng tôi đã từng muốn làm điều đó một lần nữa, bởi vì tôi Thr đau đầu.

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

Ồ vâng, xâu chuỗi, và không trở lại, phải.


Bạn có thể sử dụng 10 base>thay vì string>number?
fede s.

@fedes. Wow, tôi không bao giờ biết rằng đã tồn tại. Tôi nghĩ rằng điều đó sẽ cho phép tôi rút ngắn rất nhiều câu trả lời Yếu tố của mình!
mèo

10 >basecho số> chuỗi, cũng.
fede s.

1
@fedes. Những người xứng đáng có câu trả lời ở đây : D
mèo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.