一个简单的TCP服务器


104

编写一个程序或函数,以侦听端口N上的传入TCP通信。它提供了一种简单的服务:它计算传入连接的IP地址字段的总和并返回。

程序或函数从参数或标准输入读取整数N。它侦听端口N上的传入TCP连接。当有人连接到该端口时,该程序将计算其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或类似的东西?
Digital Trauma

91
我喜欢这样,因为打高尔夫球的挑战是打高尔夫球的语言不太可能会很好。
isaacg

9
TCP服务器显然是一个非常容易编写的程序,这不仅令人惊奇,而且我为它的乐趣而深深着迷。我将回到像FibBuzz那样挣扎的状态。
MonkeyZeus

17
@isaacg只有在有人找到Mathematica中内置的TCP服务器的时候
Downgoat

3
@MonkeyZeus公平地说,您在这里看不到任何好的 TCP服务器。制作,处理TCP(和你的应用协议)的所有复杂的可靠,可扩展的TCP服务器也有点困难:d虽然它有一定的帮助,该协议是非常简单的-你甚至都不需要读取数据流,东西我见过太多的TCP服务器坏了,无法计数:D
Luaan

Answers:


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你可以ncnetcat的传统(不,netcat的,OpenBSD是不好),并ssiproute2的


22
为什么说这不是一个严肃的解决方案?只要它能按预期运行,我就没有理由不认为它是严肃的。目前,它也是最短的一个相当大的幅度。
Alex A.

当我与@JesseSielaff讨论时,最大的担忧出现在我得知在配置了IPv6的系统上,套接字相关信息的格式可能不同。没有此类系统可以对其进行测试。为此,我在考虑将其转换为CW是否更正确。
manatwork'Mar

3
我对规范的了解是,您必须支持IPv4 IPv6,而不是两者都支持。因此,我认为,只要它适用于IPv4,不支持IPv6无关紧要。
亚历克斯A.

1
@AlexA。至少我认为我的问题是这样。我应该澄清一下吗?
汉尼斯·卡皮拉16'Mar

@HannesKarppila,您的问题很明确。可能的问题是,我的解决方案可能要求以特定方式配置操作系统才能运行。所以我很担心,因为如果配置了IPv6,无论我是否处理,它都可能会失败。配置了IPv6的人可以肯定地说出来…
manatwork'Mar

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
您可以使用int Main代替来保存1个字节void Main。由于程序从不返回,因此编译器不需要return语句。
raznagul

不,它不会泄漏。实际上,释放资源也很确定。另外,to的参数Start是可选的,保存另一个字符。
Lu安

@Luaan是的,那是调试留下的。
LegionMammal978 '16

另外,您可以using在上使用TcpClient,这将为您节省另外三个字符(使用中{}for),对进行相同操作StreamWriter也可以节省一个字符。
a安

@Luaan我需要明确FlushStreamWriter,以使其正常工作。
LegionMammal978 '16

22

Linux ELF / x86,146字节

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

包括52字节的ELF标头,32字节的程序标头,111字节的程序代码+ 3字节的代码,用于在标头内部跳过。

有关如何创建小型ELF可执行文件的信息,可以在面包箱关于为Linux创建真正的青少年ELF可执行文件的旋风教程 ”中找到

Linux / i386使用socketcall(2)Multiplex系统调用,该系统调用接受ebx特定的套接字调用(SYS_*来自的宏/usr/include/linux/net.h),并ecx指向原始库调用的参数区域的指针。

为了使可执行文件变小而做了一些事情:

  • 它假定寄存器在进入时为零,Linux这样做,但是ELF标准不要求(唯一的要求是在进入EDX终结功能的入口(对于由动态链接器加载的可执行文件有用)或为NULL)。
  • 它假定在​​启动时(通常由外壳程序启动)唯一打开的文件描述符为0、1和2。这意味着侦听套接字将为fd 3,接受的套接字将为fd 4。
  • 假设有2个参数(包括argv[0])。
  • 同样的堆栈空间被再利用于呼叫bind(2)listen(2)accept(2)
  • 跳过的phentsizephnum字段,字节被前置,变成一个CMP其取操作phentsizephnum字段作为立即(特技无耻地从被盗在混乱高尔夫球面包盒的溶液至123)。
  • 对于短代码,x86字符串操作LODS(加载到累加器和递增/递减的源索引中)和STOS(从累加器存储和递增/递减的目标索引中)是不错的选择。
  • XCHG EAX, reg是1个字节,而MOV EAX, reg则需要2个字节。
  • CDQ/CLTD(将符号扩展EAXEDX:EAX)可以用作将EDX寄存器清零的1字节方式。
  • BSWAP对于实现非常有用htons()

nasm来源:

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

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

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

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

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

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

4
这个答案被人们低估了。

16

的NodeJS,146个 134 127字节

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

我终于可以发布一个NodeJS答案!现在只有IPv4。

示例执行:node script.js 1024。从另一个终端:

$ curl 127.0.0.1:1024
128

2
我现在计算的是127个字节,尽管您可以通过换成'\n'包含文字换行符的模板字符串将其减少到126个字节。
Mwr247 '16

这不会因为满足您的要求而失败,因为您创建的是HTTP服务器,从技术上来说,它是TCP服务器,但是您不能只使用TCP模块并保存一个字符吗?
MayorMonty 2016年

14

Tcl,92

  • @DonalFellows节省了1个字节。
proc s {c a p} {puts $c [expr [string map .\ + $a]]
close $c}
socket -server s $argv
vwait f

相当不言自明:

socket -server s $argv 在参数中指定的端口上创建侦听套接字。

每次建立新连接时,proc s都会使用通道,源地址和源端口作为参数来调用。 string map替换.+在源地址,和expr算术计算结果,然后将其puts返回到连接信道c

vwait 运行事件循环以捕获传入的连接事件。


感谢@DonalFellows提供以下信息:

这是处理IPv6的版本(需要Tcl 8.6;大部分额外长度是由于产生了十六进制响应):

Tcl,109

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

1
使用apply似乎并不能节省任何东西。您也不能使用,tcl::mathop::+ {*}[split $a .]因为那会稍长一些。您也不能从选项名称中删除任何内容。但是添加IPv6支持非常简单,并且仅花费几字节的代码(然后,regsub基于方法的时间就一样长)。
Donal Fellows

啊,Tcl / Tcl-DP ...很棒的工具。(在90年代,一位教授向我们展示了我们可以编写一个由网络分发的Excel(带有网格,并包含公式求值!),这些人在服务器(iirc)4行(短)和客户端5行中共享。 ..
Olivier Dulac

proc s {c a p}您真的需要所有这些空格吗?

12

常规13312593,89

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

可能只有IPv4。

取消高尔夫:

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

测试:

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

1
.toInteger()as ints.inetAddress.address*.toInteger()(s.inetAddress.address as int[])。之后还有一个额外的空间.with
manatwork'Mar

@manatwork thx!更新。
Will 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(".","+")))
汉尼斯·卡皮拉16'Mar

2
@HannesKarppila哦,谢谢。忘记了空间,但是评估黑客还是很酷的。
萨姆科

2
AF_INET和SOCK_STREAM只是常量;AF_INET为2,SOCK_STREAM为1。此外,如上所述,SOCK_STREAM是不必要的;因此您可以改用来缩短它s=socket(2)
斯凯勒

1
你不能只是做socket()因此保存另一个字节吗?
Foon

1
您可以使用Python 2保存10个字符。然后,int(input())变为input(),发送部分变为c.send(`eval(a[0].replace(".","+"))`)
Blender

9

Java,371 368 350 344 333 310 295 282字节

打高尔夫球

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

不打高尔夫球

import java.net.*;

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

输出量

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

1
删除,int k=然后用中的所有c替换k Integer.toString(k)。要节省几个字节。
GiantTree '16

1
Java字节非常确定会
破坏

1
更改interfaceclass应该再获得几个字节
ortis

2
使用a.getOutputStream().write((c[0] + c[1] + c[2] + c[3]+"\n").getBytes());代替new DataOutputStream(a.getOutputStream()).writeBytes(c[0] + c[1] + c[2] + c[3] + "\n")
ortis

3
是不是try(Socket a=...){}比短a.close();?需要Java 7,但可以获取字节。
奥利维尔·格雷戈尔

8

PowerShell的V2 +,303个 268 257 227字节

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

多亏了Matt的帮助,节省了35个字节...通过别名New-Object和较小的调整又节省了11个字节...通过隐式使用localhost而不是anyIP地址节省了30个字节,并纠正了原来指定的连续使用情况,我错过了

确实类似于C#的答案,因为两者都是.NET的基础。我们可以利用PowerShell的返回功能(在括号中环绕我们的声明/赋值,然后立即调用。方法)在C#答案上节省一些字节,但是由于需要公式求和,因此损失了很多。我们的类名/调用稍短的事实实际上就是为什么这个答案优于C#的原因。

说明

我们首先创建一个New-Alias(使用nal别名)以保存New-Object以后再次输入。第一行的其余部分是设置TCP侦听器。我们将命令行$args[0]作为输入来创建新的System.Net.Sockets.TcpListener存储为$l。该对象被封装在括号中,并立即与之.Start()一起调用以使其主动打开套接字。

进入无限for循环,然后将侦听器设置$l为阻塞,AcceptTcpClient()等待连接。对该连接的引用(一旦建立)就存储在中$c,封装在parens中,并立即调用GetStream()以获取数据流。该数据流将传递给新的System.IO.StreamWriter构造函数$w,因此我们可以对其进行操作。该构造函数本身封装在parens中,并立即调用Write(...)

Write(...)通话中,我们将使用客户端句柄$c并获取客户端的RemoteEndPoint属性。这是(到目前为止,我已经找到的)获取远程IP地址的唯一方法。接下来,我们需要将该[System.Net.IPEndPoint]对象重新转换为正确的格式,将其封装在parens中,然后仅提取.Address属性。然后-replace,我们使用带加号的文字周期,然后将其管道传输到Invoke-Expression(类似于eval)以获得总和。

IO写入后,我们需要调用.Dispose()以确保将数据流刷新到客户端并关闭。TCP服务器会丢弃客户端连接而不会发出警告,因此,根据所使用的客户端的不同,TCP服务器可能会在此时挂起一段时间。然后,它继续for循环,而没有正确关闭连接。这也意味着它会像疯狂一样泄漏内存和系统句柄,但是我们对此并不在意,对吗?不过,运行完服务器后,您可能需要使用任务管理器来终止进程。:D

也是IPv4,因为求和框试图处理IPv6地址,这:是壮观的尝试,因为这不是有效的代数运算符进行iex解析。


2
“内存泄漏和系统处理异常疯狂”之后,您对free()它们有什么要求?delete[], 也许?:P

8
@tac是啊,有整体转换.close().dispose()方法,我们不叫这里,会导致人们对代码审查有一个合适的。
AdmBorkBork

哦,不是PS GC吗?还是GC进行计数而不是范围分析?

@tac是的,由于底层的.NET系统,PowerShell确实具有垃圾回收功能。但是,根据您调用或利用此脚本的方式,您可能会遇到诸如此类的错误,这些错误会在管道中泄漏内存。上面的代码也不是线程安全的,因此可能会遇到GC问题,因为我们没有明确关闭套接字。
AdmBorkBork

1
在测试中,我可能无法解决此问题,这可能是由于防火墙问题,我不想修复,所以我不能确定,但​​是.....我认为您可以从大多数(如果不是全部)类型转换中删除“ System”你在那里,即:[Net.ipaddress]::Any作品。
马特

7

PHP,161(56?)

这是我在这里的第一篇文章。我希望这是对的:)

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

取消高尔夫:

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

终奌站:

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

这仅适用于IPV4

编辑:我只是注意到php支持基本服务器:
我决定坚持原始字符数,除非有人确认是否允许以下​​内容:)

test2.php :(可能的56字节解决方案)

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

然后开始服务:

php -S localhost:8080 test2.php

Chrome作为客户端 屏幕截图

编辑2:wget作为客户端

$ wget -qO- localhost:8080
128

我知道规则说:“程序或函数从参数或标准输入读取整数N”,但是在这种情况下程序本身就是php可以吗?还是在php中使用内置服务器被视为漏洞?
Mikael

欢迎来到编程难题和代码高尔夫球!您的161字节解决方案看起来很棒。您在下面提到的56字节解决方案是test2.php吗?如果是这样,我认为您必须询问OP,他们是否认为这种挑战可以接受这种内置功能。不过这不是漏洞。
Alex A.

我会说,使用内置的TCP服务器是可以接受的,但是在这种情况下,我们将讨论内置的HTTP服务器。因此56字节的解决方案1)如果客户端仅连接并且不发送任何消息,则不执行任何操作;2)仅发送回“ [2016年3月30日星期三10:15:02] 127.0.0.1:47974无效的请求(格式错误的HTTP请求)”,而不会运行test2.php,以防客户端发送例如“ foo”的情况;3)如果客户端发送有效的HTTP请求,则在实际需要的响应之前发送完整的HTTP响应标头。
manatwork'Mar

@Alex A.谢谢,是的,56字节的解决方案在test2.php下:)
Mikael

@manatwork您是正确的,但我认为此任务中未明确指定客户端。那么可以使用浏览器或更简单的方式(例如“ 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服务器的好语言!
Numeri '16

1
奇怪,我得到的结果360,当我从192.168.0.67连接,而不是427
史蒂夫

3
您可以命名字符串+ strconv包以节省一些字节。例如"strings"变成s "strings"以后strings.Split成为正义s.Split
史蒂夫

1
pastebin.com/HY84sazE删除的字节数减少了-现在开始看起来有些“低沉”了
史蒂夫(Steve)

2
如果使用import(."pkgname")所有函数,将导入到当前名称空间,则可以删除前缀。例如。import ."fmt"; Println("foo") 如果您使用Sscanffmt包解析地址,而不是正则表达式,它会为你节省其他几个字节,为您提供具有漂亮的奖金Fprintln总数返回,而不是进口strconv
Kristoffer Sall-Storgaard'Mar

7

Common 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
是的,对普通科普!

6

q,88字节

system raze"p ",1_.z.x;.z.pg:{(string sum"i"$0x0 vs .z.a),"\n"};.z.ph:{.h.hy[`;.z.pg[]]}
  • system raze"p ",1_.z.x:使用第二个命令行参数(第一个"-"用于告诉您q不要将其解释N为脚本/文件),并"p "使用它打开端口()。
    • 注意:调用q -p N会将端口设置为N自动,但是由于问题似乎表明N应该将其作为程序的参数而不是可执行文件本身,因此我走了更长的路。
  • .z.pg处理传入请求的函数内部,.z.a将IP地址保留为32位整数。
    • "i"$0x0 vs将其拆分为整数“组成部分”,然后sum进行求和。
    • 最后,string将数值结果附加"\n"到其上以返回到客户端。
  • .z.ph 是HTTP GET请求的另一个功能,具有额外的处理功能,可将字符串输出转换为有效的HTTP响应。

演示-服务器:

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

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

演示-客户端(来自q上运行的另一个会话127.0.0.1):

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

演示-客户(来自curl):

$ curl localhost:1234
128

$

6

LiveScript,或者107个 105字节

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

没什么可添加的,只是基本的NodeJS东西。&1(第二个参数),<|(F#管道,类似于$Haskell中的)和biop:的样式点类似于(+)LS中的Haskell的运算符部分:咖喱函数(添加其操作数)。也有点脏:/如果在其右侧给出了文字字符串,则会进行拆分。


5

Perl,141132 + 1 = 133个字节

打高尔夫球

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

不打高尔夫球

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

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

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

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

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

    # close
    shutdown($c,1);

    redo;
}

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

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

您确定这是正确的吗?我将总和打印在服务器的终端上,而不是客户的终端上。无论如何,您可以删除所有括号并更改s/\./+/gy/./+/
manatwork'Mar

啊,误读..将作相应修改,并采纳您的良好建议。
史蒂夫

1
while(1){…}{…;redo}根据user130144提示。除->send()通话外,其他所有括号都没有必要。
manatwork'Mar

4

Python 2,180个字节

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

通过stdin进入港口。


4

的NodeJS(ES6),129个 118 107字节

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

适用于IPv4。运行为node server.js <port>


如果服务器使用的是IPv6(例如,我的自动执行),c.remoteAddress则实际上不起作用,因为那样会是::ffff:127.0.0.1。(我在Node v5.9.1上进行了测试)。
Frxstrem '16

另外,您没有结尾的换行符,它会使分数提高2个字节。
Frxstrem '16

@Frxstrem糟糕,忘记了换行符。由于模板字符串,仅增加了1个字节。关于IP系列:.listen()以前默认默认为IPv4,但似乎由于错误或设计而有所改变。当主机上禁用IPv6时,提交仍将在较新版本的节点上正常运行。
Mwr247 '16

4

Go,211个字节

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

也许可以进一步打高尔夫,例如,我对解析IP地址的方式并不完全满意,这看起来像一个可怕的骇客。

在作为参数给出的端口上侦听IPv4。


4

PowerShell中,208个 206 192 152字节

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

版本信息:

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

感谢TimmyD为我节省了14个字节!

非常感谢TessellatingHeckler为我节省了40个字节


@TimmyD啊,糟糕,我错过了这件事的必要...现在已解决
Nacht

允许程序接受输入的一种方法是来自stdin。我想这个特定的问题没有指定允许的范围,但这是我认为应该用于PowerShell的通用代码高尔夫问题。不幸的是,它与bash的不同之处在于,如果没有提供任何输入,它不会等待stdin上的输入。
Nacht

很公平。再次修复
Nacht

Alrighty,现在对于一些高尔夫的-尝试在192以下-($t=new-object net.sockets.tcplistener($args[0])).start();for(){($z=$t.acceptsocket()).send(($x=[byte[]][char[]](""+($z.remoteendpoint.address-replace"\.","+"|iex))+32),$x.count,0);$z.close()}
AdmBorkBork

1
我认为您可以将其降低到152-直接删除新对象并进行强制转换,跳过字节数组转换并以不同的方式进行字符串强制转换,根本不存储$ x并将其余参数拖放到send()上,变成了($t=[net.sockets.tcplistener]$args[0]).start();for(){($z=$t.acceptsocket()).send([char[]]"$($z.remoteendpoint.address-replace"\.","+"|iex)");$z.close()}-我仅使用netcat连接进行了快速测试,但似乎工作原理相同-无论如何都从localhost连接。
TessellatingHeckler

4

8086机器代码(16位DOS),163156148148142字节

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

假定ntcpdrvINT 0x61(以及任何合适的数据包驱动程序0x60)处已加载。用编译fasm tcpserv.asm

但是它有一些问题:

  • 它不会检查该参数是否是有效的端口号,甚至根本不是一个数字。
  • 客户端必须至少发送一个字节,因为我似乎无法找到其他方法来判断客户端是否已连接。
  • 它只能工作一次,然后挂起第二次尝试。重新启动后可以再次使用。
  • 返回的值用零左填充。
  • 这是我的第一个高尔夫入门代码,也是我的第一个8086 asm程序。我敢肯定有办法进一步改善这一点。

1
你可以只发布编译输出的hexdump都为148个字节

可以吗 这将使该条目更具竞争力...
user5434231 16-4-8

1
好了,我已将条目更改为机器代码。还使用xor r,r代替减少了几个字节mov r,0
user5434231 '16

1
我是在换行符所在的dos机器上写的CR LF,所以我就这么做了。不管哪种方式,现在计算一下asm的大小都毫无意义,不妨稍微清理一下并添加一些注释。
user5434231 2016年

1
这也应该在这里发生,并且确实有效。int 0x61返回中的随机本地端口ax。但它也会将侦听IP更改为某些垃圾编号(4.2.0.0iirc)
2016年

3

Haskell,216个字节

使用“简单网络”程序包(cabal install network-simple)。需要几个语言扩展名(-XOverloadedStrings -XNoMonomorphismRestriction)才能工作。

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

有两种可能的简化,包括更改w函数以直接返回总和而不是列表,并使用函数而不是程序,以便可以将端口号指定为参数。我不认为这会大大减小尺寸。也许20个字节?


真好!敢肯定你仍然可以通过重命名刮胡子几个字节断w#,所以w h n成为h#n了每使用2个字节的节省。
Actorclavilis

3

腮腺炎,114个 115字节

打高尔夫球:

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

取消高尔夫:

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

这是InterSystemsCaché版本的Mumps-如果有一个版本可以获取比##class(%SYSTEM.TCPDevice).PeerAddr() 短的TCP地址(因为它几乎是整个程序的1/3),那么它可能有更好的机会抵御已经发布的其他一些语言... ;-)

编辑:感谢@TimmyD-我错过了从STDIN或参数而不是硬编码读取端口的信息。编辑; 它向程序添加了1个字节。


@TimmyD-嗯,是的。通过阅读要求错过了。将编辑后期处理。
zmerch '16

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。
汉尼斯·卡皮拉'16

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),而不必显式调用socketbindlisten分别。但是,可悲的是,Network.accept给我一个主机字符串,而不是IP地址整数,所以我不得不求助于Network.Socket.accept和朋友。

该函数f将端口号作为参数,并创建一个s侦听该端口的服务器套接字()。然后,它g使用服务器套接字调用该函数。g永远循环,接受连接。该函数b获取实际的IPv4地址,并计算其数字的总和。

我确信某个地方的人可以比我做得更好。我想炫耀Haskell中简单的套接字东西是多么可恶...但是随后失败了,因为我需要访问通常不容易获得的IP地址。


“简单网络”程序包提供了一个更好的接口,该接口将SockAddr传递给您提供的函数,这使事情变得更加容易。看看我要发布的解决方案...
Jules

显然有一些简化:(1)我相信withSocketsDo仅在Windows上才有必要,因此,如果在Linux上运行,则可以忽略;(2)0xFF是大于255的字符;(3)将套接字转换为手柄并使用常规IO比使用IO要长得多Network.Socket.send。是的,send已弃用,但原因与这种情况无关(它仅与非ASCII文本或二进制数据有关),因此使用它似乎是合理的。
Jules

Network.accept gives me a host string, not an IP address integer你就不能拆分的知识产权字符串"."mapHaskell的字符串到数字功能在分割字符串,总结的结果?

2

卢阿 169 162 160 153 151 148 138 129字节

高尔夫版

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

它需要安装Luasocket和一个支持标签的解释器。我已经用Luajit对其进行了测试,并且我还可以确认该代码不适用于Lua 5.1。

非高尔夫版本

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

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

c:close()
goto l

编辑1:

更改i=({c:getpeername()})[1]i=c:getpeername()

编辑2:

从require语句中删除了括号。

编辑3:

删除了可变参数周围的花括号,将字节数减少了一点。

编辑4:

删除了“%d +”周围的括号,该括号缩短了2个字节。

编辑5:

删除了不必要的变量i。

编辑6:

将ip从“ 127.0.0.1”更改为0。(感谢#lua上的xyzzy)

编辑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)

将端口号作为标准输入上的一行;需要network-simple来自Cabal。

通常,Haskell的答案不会将自己限制在纯函数上,因此imports占用了太多字节。尾随的换行符也值9个字节...

有点类似于@Jules的答案,但是我使用字符串操作而不是字节操作。我还盗用-XOverloadedStrings扩展名,它可能额外值得19个字节。


2

C,243188字节(或者可能是217162字节)

V2:请参阅以下说明。

188个字节:

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

略为162个字节:

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

明天早上可能会打更多的高尔夫球。这些更新后,我会整理这篇文章。


V1:

高尔夫真的很有趣。

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

它适用于IPv4。通常,这是一个简单的实现。三个主要组成部分是

创建套接字:

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

我们使用常量AF_INET等的各种显式形式,并利用以下事实:当以这种方式在C中初始化结构时,未指定的元素将设置为零。

倾听客户,接受他们并关闭他们的联系:

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

IP存储C.sin_addr.s_addr为32位整数,其中每个八位位组由四个字节之一表示。我们将这些字节与for循环求和,然后使用fprintf将它们打印到流中。

我有一个较短的217字节解决方案,但是我不能完全确定它没有违反标准漏洞,因为它要求端口以网络字节顺序作为命令行参数以一元形式给出。也就是说,要在端口12345上运行服务器,需要调用

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

其中1s 的总数为14640。至少可以说这有点...麻烦。但是无论如何,这里是:

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

2

球拍,265字节

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

取消高尔夫:

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

2

因子,155个 146 131 206 190字节

好吧,我刚刚学到了很多有关底层套接字编程的知识。我不认为我永远不想说再这样做,因为我的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。哇,我不知道那是存在的。我认为这将使我能够缩短许多因素答案!
2016年

10 >base对于数量>字符串,也。
fede s。

1
@fedes。那些应该在这里得到答案:D
cat
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.