程序代码:
#include <stdio.h> /* */
#include <stdlib.h> /* exit() */
#include <string.h> /* memset(), memcpy() */
#include <sys/utsname.h> /* uname() */
#include <sys/types.h>
#include <sys/socket.h> /* socket(), bind(),
listen(), accept() */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h> /* fork(), write(), close() */
/*
* prototypes
*/
int _GetHostName(char *buffer, int length);
/*
* constants
*/
const char MESSAGE[] = "Hello, World!\n";
const int BACK_LOG = 5;
int main(int argc, char *argv[])
{
int serverSocket = 0,
on = 0,
port = 0,
status = 0,
childPid = 0;
struct hostent *hostPtr = NULL;
char hostname[80] = "";
struct sockaddr_in serverName = { 0 };
if (2 != argc)
{
fprintf(stderr, "Usage: %s <port>\n",
argv[0]);
exit(1);
}
port = atoi(argv[1]);
serverSocket = socket(PF_INET, SOCK_STREAM,
IPPROTO_TCP);
if (-1 == serverSocket)
{
perror("socket()");
exit(1);
}
/*
* turn off bind address checking, and allow
* port numbers to be reused - otherwise
* the TIME_WAIT phenomenon will prevent
* binding to these address.port combinations
* for (2 * MSL) seconds.
*/
on = 1;
status = setsockopt(serverSocket, SOL_SOCKET,
SO_REUSEADDR,
(const char *) &on, sizeof(on));
if (-1 == status)
{
perror("setsockopt(...,SO_REUSEADDR,...)");
}
/*
* when connection is closed, there is a need
* to linger to ensure all data is
* transmitted, so turn this on also
*/
{
struct linger linger = { 0 };
linger.l_onoff = 1;
linger.l_linger = 30;
status = setsockopt(serverSocket,
SOL_SOCKET, SO_LINGER,
(const char *) &linger,
sizeof(linger));
if (-1 == status)
{
perror("setsockopt(...,SO_LINGER,...)");
}
}
/*
* find out who I am
*/
status = _GetHostName(hostname,
sizeof(hostname));
if (-1 == status)
{
perror("_GetHostName()");
exit(1);
}
hostPtr = gethostbyname(hostname);
if (NULL == hostPtr)
{
perror("gethostbyname()");
exit(1);
}
(void) memset(&serverName, 0,
sizeof(serverName));
(void) memcpy(&serverName.sin_addr,
hostPtr->h_addr,
hostPtr->h_length);
/*
* to allow server be contactable on any of
* its IP addresses, uncomment the following
* line of code:
* serverName.sin_addr.s_addr=htonl(INADDR_ANY);
*/
serverName.sin_family = AF_INET;
/* network-order */
serverName.sin_port = htons(port);
status = bind(serverSocket,
(struct sockaddr *) &serverName,
sizeof(serverName));
if (-1 == status)
{
perror("bind()");
exit(1);
}
status = listen(serverSocket, BACK_LOG);
if (-1 == status)
{
perror("listen()");
exit(1);
}
for (;;)
{
struct sockaddr_in clientName = { 0 };
int slaveSocket, clientLength =
sizeof(clientName);
(void) memset(&clientName, 0,
sizeof(clientName));
slaveSocket = accept(serverSocket,
(struct sockaddr *) &clientName,
&clientLength);
if (-1 == slaveSocket)
{
perror("accept()");
exit(1);
}
childPid = fork();
switch (childPid)
{
case -1: /* ERROR */
perror("fork()");
exit(1);
case 0: /* child process */
close(serverSocket);
if (-1 == getpeername(slaveSocket,
(struct sockaddr *) &clientName,
&clientLength))
{
perror("getpeername()");
}
else
{
printf("Connection request from %s\n",
inet_ntoa(clientName.sin_addr));
}
/*
* Server application specific code
* goes here, e.g. perform some
* action, respond to client etc.
*/
write(slaveSocket, MESSAGE,
strlen(MESSAGE));
close(slaveSocket);
exit(0);
default: /* parent process */
close(slaveSocket);
}
}
return 0;
}
/*
* Local replacement of gethostname() to aid
* portability */
int _GetHostName(char *buffer, int length)
{
struct utsname sysname = { 0 };
int status = 0;
status = uname(&sysname);
if (-1 != status)
{
strncpy(buffer, sysname.nodename, length);
}
return (status);
}
如果把
on = 1;
status = setsockopt(serverSocket, SOL_SOCKET,
SO_REUSEADDR,
(const char *) &on, sizeof(on));
if (-1 == status)
{
perror("setsockopt(...,SO_REUSEADDR,...)");
}
注释掉, 就会发现编译之后,多次运行
$ ./a.out 5555
会得到错误
bind(): Address already in use
这就是
SO_REUSEADDR的作用了