Ein Server besitzt einen Socket auf dem er lauschenderweise Clients erwartet. Wenn ein solcher Client auftaucht, kann er mit accept() abgeholt werden. Da dieser Aufruf blockieren kann, ist es besonders bequem: man ruft accept() auf und muß nichts weiter tun, als auf die Rückkehr zu warten.
Unser Server soll einfach alles zurücksenden, das vom Client kommt. Das entspricht dem echo-Dienst, der normalerweise auf Port 7 wartet. Unser Service wird auf Port 7000 warten, damit der Code von normalen Benutzern getestet werden kann (denn auf die Ports < 1024 kann ja nur root zugreifen).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define BUF_SIZ 4096
int handle_client(const int sock)
{
char buffer[BUF_SIZ];
int bytes;
/* Erinnerung: wenn recv() als Rueckgabe 0 liefert, dann
* wurde die Verbindung geschlossen. Daher hier auf > 0 und
* nicht auf == -1 testen.
*/
while((bytes = recv(sock, buffer, sizeof(buffer), 0)) > 0)
send(sock, buffer, bytes, 0);
return 0;
}
int main(void)
{
int s, c;
socklen_t addr_len;
struct sockaddr_in addr;
s = socket(PF_INET, SOCK_STREAM, 0);
if (s == -1)
{
perror("socket() failed");
return 1;
}
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(7000);
addr.sin_family = AF_INET;
if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) == -1)
{
perror("bind() failed");
return 2;
}
if (listen(s, 3) == -1)
{
perror("listen() failed");
return 3;
}
for(;;)
{
addr_len = sizeof(addr);
c = accept(s, (struct sockaddr*)&addr, &addr_len);
if (c == -1)
{
perror("accept() failed");
continue;
}
printf("Client from %s\n", inet_ntoa(addr.sin_addr));
handle_client(c);
close(c);
}
close(s);
return 0;
}