2013年9月6日 星期五

TCP nonblock socket server and client

Server:
static void Init_Server(int port)
{
  int                             err, flags;
  struct sockaddr_in    server_addr;

  s_server_fd = socket(AF_INET, SOCK_STREAM, 0);
  if (s_server_fd < 0)
      on_error("Could not create server_addr socket: %s\n", strerror(errno))

  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(port);
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

  int opt_val = 1;
  setsockopt(s_server_fd, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val));

  err = bind(s_server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr));
  if (err < 0)
      on_error("Could not bind server_addr socket: %s\n", strerror(errno));

  flags = fcntl(s_server_fd, F_GETFL, 0);
  if (flags < 0)
      on_error("Could not get server_addr socket flags: %s\n", strerror(errno))

  err = fcntl(s_server_fd, F_SETFL, flags | O_NONBLOCK);
  if (err < 0) on_error("Could set server_addr socket to be non blocking: %s\n", strerror(errno));

  err = listen(s_server_fd, SOMAXCONN);

  if (err < 0)
      on_error("Could not listen: %s\n", strerror(errno));
}

static int Accept_Coming ()
{
    int                             err;
    int                             flags;
    int                             client_fd;
    struct sockaddr        client_addr;
    socklen_t                 client_len;

    client_fd         = accept(s_server_fd, &client_addr, &client_len);
    client_len     = sizeof(client_addr);

    if (client_fd < 0)
    {
        if (errno == EWOULDBLOCK || errno == EAGAIN)
            return 0;

        on_error("Accept failed (should this be fatal?): %s\n", strerror(errno));
    }

    flags = fcntl(client_fd, F_GETFL, 0);
    if (flags < 0)
        on_error("Could not get client socket flags: %s\n", strerror(errno));

    err = fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);

    if (err < 0)
        on_error("Could not set client socket to be non blocking: %s\n", strerror(errno));

    return client_fd;
}


///Another way to use select maxfd+1(at least +1) to make non-block server///
FD_ZERO(&svfset);
FD_SET(s_serversocket, &svfset);

while( s_thread_work )
{
    rdset = svfset;
    //use select monitor all sockets of list
    if (select(maxfd+1, &rdset, NULL, NULL, NULL) == -1)
    {
        s_thread_work = 0; //exit while loop
        printf("Server select failure \n");
    }

    /////////New  client and data receive/////////
    node_ptr = List_NetGetFirstNode();
    while( node_ptr )
    {
        if (FD_ISSET(node_ptr->socketfd, &rdset))
        {
            //if (current_socket == s_serversocket)
            if( node_ptr->socketfd == s_serversocket )
            {
                /* Handle new connections */
                addrlen = sizeof(clientaddr);
                memset(&clientaddr, 0, sizeof(clientaddr));
                acceptfd = accept(s_serversocket, (struct sockaddr*)&clientaddr, &addrlen);

                if (acceptfd <= -1)
                {
                    printf("Server accept error \n");
                }
                else
                {
                    FD_SET(acceptfd, &svfset);

                    if (acceptfd > maxfd)
                    {
                        /* Keep track of the maximum */
                        maxfd = acceptfd;
                    }

                    List_NetAddRear(acceptfd);
                    printf("New connection IP %s\n", inet_ntoa(clientaddr.sin_addr));
                    printf("Accept / maxfd = %d\n\n", maxfd);
                }
            }
            else
            {
                len = recv(node_ptr->socketfd, buf, sizeof(buf), 0);
                node_ptr->tick_last = GetNowTick();

                if (len > 0)
                {
                    //do your work
                    Buf_Job(node_ptr->socketfd, buf, len);
                }
                //else if (len == -1)
                else
                {
                    FD_CLR(node_ptr->socketfd, &svfset);
                    if (node_ptr->socketfd >= maxfd)
                    {
                        /* Keep track of the maximum */
                        maxfd--;
                    }
                    shutdown(node_ptr->socketfd, SHUT_RDWR);
                    close(node_ptr->socketfd);
                    printf("Disconnect remove socket %d\n", node_ptr->socketfd);
                    printf("Disconnect and maxfd = %d\n", maxfd);

                    node_ext.next = node_ptr->next;
                    List_NetDeletebyNode(node_ptr);
                    node_ptr = &node_ext;
                }
            }
        }//if (FD_ISSET(node_ptr->socketfd, &rdset))
        node_ptr = node_ptr->next;
    }//while(node)
}   


Client:
opts = fcntl(sockfd, F_GETFL);
if(opts < 0)
{
    fprintf(stderr, "fcntl(F_GETFL) failedn");
}

opts = (opts | O_NONBLOCK);
if(fcntl(sockfd, F_SETFL, opts) < 0)
{
    fprintf(stderr, "fcntl(F_SETFL) failedn");
}

source download:
http://www.mediafire.com/file/d649td73n6cwx74/nonblock_socket.zip
http://www.mediafire.com/file/5c7g9bt5mh2c6mj/server_multiclient.tar.gz

沒有留言:

張貼留言