Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Write a program or function that listens for incoming TCP traffic on port N. It offers a simple service: it calculates sum of IP address fields of incoming connection and returns.

Program or function reads integer N from arguments or stdin. It listens to incoming TCP connections on port N. When someone connects to that port, the program calculates sum of its IP address fields and sends it back to the client with trailing newline and closes connection.

  • Port number N is a valid port, and 210 < N < 215
  • Trailing newline can be either \nor \r\n
  • You can use either IPv4 or IPv6. Since IPv6 addresses are written in hexadecimal form, you must also provide result in same format, for example 2001:0db8:0000:0042:0000:8a2e:0370:7334 => 12ecd.

This is . Standard rules and loopholes apply.

Example

You run your server with ./server 1234. The server is now running and waiting for connections on port 1234. Then a client from 127.0.0.1 connects to your server. Your server performs a simple calculation: 127+0+0+1 => 128 and sends the result to the client (with trailing newline): 128\n. Then server closes connection and waits for next client.

share|improve this question
    
Is it allowed to use inetd/xinetd or similar? – Digital Trauma 4 hours ago
9  
I like this, since it's a golfing challenge that golfing languages are unlikely to be very good at. – isaacg 3 hours ago

12 Answers 12

Bash + netcat + ss + …, 65 characters

nc -lp$1 -c"ss src :$1|sed -z 's/.* \b//;y/.:/+#/'|bc"
exec $0 $1

Not a serious solution, was just curious about this possibility.

Sample run:

(terminal 1)

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

(terminal 2)

bash-4.3$ nc localhost 8080
128

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

On Ubuntu you can get nc from netcat-traditional (no, netcat-openbsd is not good) and ss from iproute2.

share|improve this answer
4  
Why do you say it isn't a serious solution? As long as it works as expected I see no reason why it shouldn't be considered serious. It's also the shortest by a pretty significant margin at the moment. – Alex A. 6 hours ago
    
The biggest concern against it appeared during discussion with @JesseSielaff when I learned that on systems with configured IPv6, socket related information may be formatted differently. Have no such system to test it. For which I'm thinking whether would be more correct to turn it into CW. – manatwork 5 hours ago

C#, 284 bytes

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

Classic example of a basic C# TCP server. Don't run this for too many clients, as it leaks memory (I think). Testing:

Terminal 1:

$ ./Q76379.exe 1029

Terminal 2:

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

Firefox:

share|improve this answer

Ruby 2.3, 122 105 92 76+7 = 83 bytes

IPV4 only. Port number is first argument.

Golfed

Socket.tcp_server_loop$*[0]{|c,a|c.puts eval a.ip_address.tr'.',?+;c.close}

Ungolfed

require 'socket'

port = ARGV[0]
Socket.tcp_server_loop(port) do |client, addrinfo|
  ipv4_addr_str = addrinfo.ip_address
  sum = eval ipv4_addr_str.tr('.', '+')
  client.puts(sum)
  client.close
end

Output

$ ruby -rsocket server 1234 &
$ nc localhost 1234 -4
128
share|improve this answer
2  
You can replace the .split + .map + .reduce calculation with eval c.addr[-1].tr ?.,?+. By the way, why the regular expression thing? In .addr[-1] I get only the IP address. – manatwork 6 hours ago
    
@manatwork That's a good idea if you can guarantee a simple numerical IP address like '127.0.0.1', but c.addr[-1] returns '::ffff:127.0.0.1' for me when I hit it from localhost. – Jesse Sielaff 6 hours ago
1  
Oh, so that is the reason. I have absolutely no IPv6 configuration here so without you would never find out there can be such additional stuff. Thanks, @JesseSielaff. – manatwork 6 hours ago
    
@manatwork your eval hack still works on the regex'd string. I updated the answer to use it. – Jesse Sielaff 6 hours ago
    
Welcome to Programming Puzzles & Code Golf! This is a great first answer. – Alex A. 6 hours ago

Python 3, 170 166 147 bytes

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

Takes port on stdin, IPv4 only. Works on GNU/Linux (and, I assume, most other unices), which automatically expands "" to "0.0.0.0", not sure about Windows though.

share|improve this answer
2  
You could save several bytes. Firstly, spaces in import * and , SOCK_STREAM are unnecessary. Also, the send line could be written more efficiently as c.send(b"%d\n"%eval(a[0].replace(".","+"))). – Hannes Karppila 10 hours ago
1  
@HannesKarppila oh, thanks. forgot about the spaces, the eval hack is pretty cool though. – sammko 10 hours ago
2  
AF_INET and SOCK_STREAM are just constants; AF_INET is 2 and SOCK_STREAM is 1. Also, as mentioned, SOCK_STREAM is unnecessary; so you can shorten that by instead using s=socket(2). – Skyler 4 hours ago
1  
can't you just do socket() and therefore save another byte? – Foon 4 hours ago
    
Although unless i'm missing something, you need to pass something to s.listen() – Foon 3 hours ago

PowerShell v2+, 303 268 bytes

($l=new-object Net.Sockets.TcpListener (New-Object Net.IPEndPoint([net.ipaddress]::Any,$args[0]))).Start()
($w=new-object IO.StreamWriter(($c=$l.AcceptTcpClient()).GetStream())).Write((([Net.IPEndPoint]$c.Client.RemoteEndPoint).Address-replace"\.",'+'|iex))
$w.Flush()

Saved 35 bytes thanks to Matt

Leaks memory and system handles like crazy, but we don't care about that, right? :D

Really similar to the C# answer, since it's .NET underlying both. We save a few bytes here over the C# answer by being able to leverage the returning functionality of PowerShell (surrounding our declaration/assignment in parens, and then immediately calling the . methods), but we lose an awful lot by needing to formulate the summation.

The only way (that I've found so far) to get the remote IP address is via the .RemoteEndPoint property, so there's a bunch of string manipulation to get just the IP portion, then -replace the literal periods with plus signs, then pipe it to Invoke-Expression (similar to eval).

If I can figure out some alternate way to get the client's IP address, I should be able to shave a lot of bytes, and maybe even beat the C# answer. But, I'm not hopeful.

share|improve this answer
1  
"Leaks memory and system handles like crazy" What, do you have to free() them after? delete[], maybe? :P – tac 7 hours ago
2  
@tac Yeah, there's a whole slew of .close() and .dispose() methods we're not calling here that would cause people on Code Review to have a fit. – TimmyD 7 hours ago
    
Oh, isn't PS GC'd? Or does the GC do refcounting and not scope-analysis? – tac 7 hours ago
    
@tac Yes, PowerShell does have garbage collection thanks to the underlying .NET system. But, depending on how you're calling or leveraging this script, you can run into bugs like this one leaking memory in the pipeline. The above code also isn't thread-safe, and so can run into GC issues with that, since we're not explicitly closing the socket. – TimmyD 7 hours ago
    
In testing I could not get this to work, likely due to firewall issues that I don't feel like fixing so I cannot be sure but..... I think you can drop "System" from most if not all the type casts you have there ie: [Net.ipaddress]::Any works. – Matt 6 hours ago

Groovy 133, 125, 93, 89

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

IPv4 only, probably.

Ungolfed:

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

Testing:

$ telnet localhost 9000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
128
Connection closed by foreign host.
share|improve this answer
1  
.toInteger()as int and s.inetAddress.address*.toInteger()(s.inetAddress.address as int[]). And there is an extra space after .with. – manatwork 5 hours ago
    
@manatwork thx! Updated. – Will P 4 hours ago

LiveScript, 107 bytes

(require 'http')createServer(->&1.end((.reduce (+))<|it.connection.remoteAddress/'.'))listen process.argv.0
share|improve this answer

q, 88 bytes

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: Takes the second command-line argument (the first "-" is for telling q not to interpret N as a script/file) and opens a port ("p ") with it.
    • Note: Calling q -p N sets the port as N automatically, but since the question seems to suggest that N should be an argument to the program rather than the executable itself, I've gone the longer way.
  • Inside the .z.pg function that handles incoming requests, .z.a holds the IP address as a 32-bit integer.
    • "i"$0x0 vs splits it into its integer 'constituents', and sum does the summation.
    • Last, string the numeric result and append "\n" to it to return to the client.
  • .z.ph is another function for HTTP GET requests, with extra handling to convert the string output into a valid HTTP response.

Demo - Server:

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 - Client (from another q session running on 127.0.0.1):

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

Demo - Client (from curl):

$ curl localhost:1234
128

$
share|improve this answer

Java, 371 368 350 344 333 bytes

Golfed

import java.io.*;import java.net.*;interface A{public static void main(String[]n)throws Exception{ServerSocket s=new ServerSocket(Integer.parseInt(n[0]));for(;;){Socket a=s.accept();byte[]c=a.getInetAddress().getAddress();new DataOutputStream(a.getOutputStream()).writeBytes(Integer.toString(c[0]+c[1]+c[2]+c[3])+"\n");a.close();}}}

Ungolfed

import java.io.*;
import java.net.*;

interface A {
    public static void main(String[] n) throws Exception {
        ServerSocket s = new ServerSocket(Integer.parseInt(n[0]));
        for (;;) {
            Socket a = s.accept();
            byte[] c = a.getInetAddress().getAddress();
            new DataOutputStream(a.getOutputStream()).writeBytes(Integer.toString(c[0] + c[1] + c[2] + c[3]) + "\n");
            a.close();
        }
    }
}

Output

mallard@steamroller:~$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
128
Connection closed by foreign host.
share|improve this answer
    
Remove the int k= and replace the k with all the c things in Integer.toString(k). To save a few bytes. – GiantTree 9 hours ago
    
You can also drop the space after your square brackets. – SuperJedi224 8 hours ago
1  
+1 for, y'know, java. – ardaozkal 8 hours ago
1  
@ardaozkal +1 for, y'know, "+1 for, y'know, Java" – tac 7 hours ago
1  
Javas byte pretty sure messes up the return value for 192.168.2.1 or similar adresses with a byte above 127. – AlexR 5 hours ago

NodeJS, 146 bytes

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

I finally get to post a NodeJS answer! IPv4 only right now.

Sample execution: node script.js 1024. From another terminal:

$ curl 127.0.0.1:1024
128
share|improve this answer

Tcl, 93

proc s {c a p} {puts $c [expr [string map {. +} $a]]
close $c}
socket -server s $argv
vwait f

Fairly self-explanatory. socket -server s $argv creates a listening socket on the port specified in the arguments. Every time a new connection arrives, the proc s is called, with channel, source-address and source-port as parameters. string map substitutes . for + in the source address, and expr arithmetically evaluates the result, which is then puts back to the connection channel c. vwait runs an event loop to catch the incoming connection events.

share|improve this answer

Perl, 141 + 1 = 142 bytes

Golfed

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

Ungolfed

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

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

Example

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

$ 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.
$
share|improve this answer
    
Are you sure this is correct? I get the sum printed in the server's terminal, not the client's. Anyway, you can remove all parenthesis and change s/\./+/gy/./+/. – manatwork 4 hours ago
    
Ahh, misread..will revise accordingly and incorporate your good y/ suggestion. – steve 4 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.