【Socket】linux网络多路复用IO技术

来源:互联网 发布:不明觉厉等网络流行语 编辑:程序博客网 时间:2024/06/04 20:28

1.mystery引入

 

   1)Select是一种多路复用IO输入输出模式,在linux的输入输出编程中通过select的轮询机制,发现可用/可读或可写的接口。
   2)低级socket程序中有一个共同点:都是基于阻塞式的编程方式
   3)非阻塞式是函数调用时不阻塞,不管函数执行成功与否,都会立即返回。
   4)优点:程序效率提升
   5)缺点:返回的结果往往是错误的类型码
   6)解决方案:Select机制。


2.实例操

 

   1)基于Select模式实现一个网络echo的服务程序,即客户端向服务端发送信息,服务器接收到信息后,再将信息原样转发给客户端
   2)需要设置Select函数
   3)若当前有新连接,则加入到客户端套接字集合,若数量过载,则断开本次连接,并发送提示信息:sorry overload
   4)源代码
//selectsocket.c#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#define SERVER_PORT 5555 #define QUEUE_LENGTH 5  #define BUF_SIZE 200int main(void){    int server_socket, new_socket;    struct sockaddr_in server_addr;     struct sockaddr_in client_addr;    socklen_t sin_size;    int client_socket[QUEUE_LENGTH];     int conn_num;     int yes = 1;    char buf[BUF_SIZE];    int ret;    int i;    if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)    {        perror("socket");        return 0;    }    if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)    {        perror("setsockopt");        return 0;    }    server_addr.sin_family = AF_INET;          server_addr.sin_port = htons(SERVER_PORT);      server_addr.sin_addr.s_addr = INADDR_ANY;    memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)    {        perror("bind");        return 0;    }    if (listen(server_socket, 5) == -1)    {        perror("listen");        return 0;    }    printf("listen port %d\n", SERVER_PORT);    fd_set clientfdset;    int maxsock;    struct timeval tv;    conn_num = 0;    sin_size = sizeof(client_addr);    maxsock = server_socket;    while (1)    {        // initialize file descriptor set        FD_ZERO(&clientfdset);        FD_SET(server_socket, &clientfdset);        // timeout setting        tv.tv_sec = 15;        tv.tv_usec = 0;        // add active connection to fd set        for (i = 0; i < QUEUE_LENGTH; i++)        {            if (client_socket[i] != 0)            {                FD_SET(client_socket[i], &clientfdset);            }        }        ret = select(maxsock + 1, &clientfdset, NULL, NULL, &tv);        if (ret < 0)        {            perror("select");            break;        }        else if (ret == 0)        {            printf("waitting timeout\n");            continue;        }        // check every fd in the set        for (i = 0; i < conn_num; i++)        {            if (FD_ISSET(client_socket[i], &clientfdset))            {                ret = recv(client_socket[i], buf, sizeof(buf), 0);                if (ret <= 0)                {                         printf("client[%d] close\n", i);                    close(client_socket[i]);                    FD_CLR(client_socket[i], &clientfdset);                    client_socket[i] = 0;                }                else                {                      printf("Client[%d] msg:%s\n", i, buf);                    send(client_socket[i], buf, sizeof(buf), 0);                }            }        }        if (FD_ISSET(server_socket, &clientfdset))        {            new_socket = accept(server_socket, (struct sockaddr *)&client_addr, &sin_size);            if (new_socket <= 0)            {                perror("accept");                continue;            }            if (conn_num < QUEUE_LENGTH)            {                client_socket[conn_num++] = new_socket;                printf("new client[%d] %s:%d\n", conn_num,                    inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));                if (new_socket > maxsock)                    maxsock = new_socket;            }            else            {                send(new_socket, "sorry overload!", sizeof("sorry overload!"), 0);                close(new_socket);                break;            }        }    }    for (i = 0; i < QUEUE_LENGTH; i++)    {        if (client_socket[i] != 0)        {            close(client_socket[i]);        }    }}




3.mystery注

 

   1)设置高级socket属性参数中的应用参数SO_REUSERADDR,实现地址的可重复利用
   2)FD_SET(int fd, fd_set *fdset):向文件描述符集合中增加一个新的文件描述符

   3)FD_CLR(int fd, fd_set *fdset):向文件描述符集合中删除一个文件描述符

原创粉丝点击