注册 登录
编程论坛 Linux系统管理

socket option: SO_REUSEADDR选项一例

madfrogme 发布于 2012-08-24 09:01, 7565 次点击
程序代码:

#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的作用了
0 回复
1