socket编程—select方法使用

原创 2016年05月31日 20:11:18

0.背景

最近要写一个RPC库,即在客户端向服务端发送请求,服务器计算并返回结果,要求实现服务端能同时接收多个客户端请求但是不能使用线程库,根据提示我知道了可以使用select函数来完成非阻塞方式工作的程序,于是我就开始了select方法的学习。

1.概念

Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序(比如我),他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。
可是使用Select就可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。

2.编程

我第一步是准备先熟悉select的简单使用,所以我在我的CentOS服务器上先编辑好如下代码:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/select.h>
#include<sys/un.h>
#include<string.h>
#include<arpa/inet.h>
int main()
{
        int server_fd;
        int client_fd;
        struct sockaddr_in myaddr;
        struct sockaddr_in clientaddr;
        int clientaddr_len=sizeof(clientaddr);
        int maxfdp;
        fd_set fds;
        struct timeval timeout={3,0};
        myaddr.sin_family=AF_INET;
        myaddr.sin_addr.s_addr=htonl(INADDR_ANY);
        myaddr.sin_port=htons(4600);
        char buf[16];
        //socket
        server_fd=socket(AF_INET,SOCK_STREAM,0);
        if(server_fd==-1)
        {
                perror("socket error");
                exit(1);
        }
        //bind
        if(bind(server_fd,(struct sockaddr *)&myaddr,sizeof(myaddr))==-1)
        {
                perror("bind error");
                exit(1);
        }
        //listen
        if(listen(server_fd,20)==-1)
        {
                perror("listen error");
                exit(1);
        }
        printf("listening~\n");
        client_fd=accept(server_fd,(struct sockaddr *)&clientaddr,&clientaddr_len);
        while(1)
        {
                FD_ZERO(&fds);
                FD_SET(server_fd,&fds);
                FD_SET(client_fd,&fds);
                maxfdp=server_fd>client_fd?server_fd+1:client_fd+1;
                switch(select(maxfdp,&fds,&fds,NULL,&timeout))
                {
                        case -1:
                                exit(-1);
                                break;
                        case 0:
                                sleep(2);
                                printf("time out~ \n");
                                break;
                        default:
                                if(FD_ISSET(client_fd,&fds))
                                {
                                        sleep(2);
                                        recv(client_fd,buf,100,0);
                                        printf("receive from client %s\n",buf);
                                }
                }
        }

        close(server_fd);
}

客户端程序比较简单,所以我就不上代码了,这里重点想讨论一下我在完成这个程序中遇到的问题。

3.问题

在完成这个程序之前我看过许多解释select方法的博客,有Windows环境下的,有linux环境下的,但是都没有能正确运行的代码,我想大家也是为了捍卫自己的版权,所以贴的都是伪码,不过也多亏了大家的共享精神我最终才能解决这些小问题。

1)在使用fd_set这个结构体声明变量的时候,我本来写的是:

struct fd_set fds

这也是很多博主的写法,但是我这样写在CentOS下用gcc编译会报错,搜索那个错误提示也没有找到相关联的答案,所以我就去掉了前面的struct关键字,然后一套编译下来,居然连一个警告都没有就通过了。

2)原本我根据别人的代码模仿着写的时候在监听之后并没有写accept这个过程,因为别人都没写哭,然后编译通过没问题,运行起来的时候就一直处于监听状态了,我在客户端反复执行连接都没有任何反应,所以,别人的方法终究只能作为参考啊,最后还是需要自己动手动脑。

3)我在网上又搜索了一阵子之后,意识到了上面那个问题,所以同样依葫芦画瓢将accept方法写在了死循环里面,但是在FD_ISSET方法判断socket描述符是否可读写时,我又犯了一个错,因为我判断的是server_fd,这个描述符无论有没有连接请求状态都是不变的,所以在调试程序的时候同样无法连通。

最后意识到上述问题之后,我想到,既然select要检测的是变幻的socket描述符,那结合之前accept方法返回的客户端描述符,怎么做方法就很明显了,即用select方法来检测accept返回的文件描述符,也就是有客户端连接请求就可以在select的switch语句中进行发送和接收了,如程序所示。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

socket select函数的详细讲解

原型int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,const struct timeval* timeo...
  • gooer
  • gooer
  • 2009-03-02 23:41
  • 90037

Linux网络编程:TCP服务器(单进程多用户),使用select方法实现

Linux下的单进程多用户TCP服务器,采用select方法实现。 [cpp] view plaincopy /********************...

Linux网络编程:TCP服务器(单进程多用户),使用select方法实现

Linux下的单进程多用户TCP服务器,采用select方法实现。 /************************************************* * File nam...

Python BeautifulSoup4 select方法执行css选择器

初识爬虫,使用urllib结合强大的BeautifulSoup简单写了下代码。看参考书上主要讲解了find方法的使用,但发现其是还支持css选择器语法选择,于是试验了一下。环境为:ubuntu12.0...

寻找最小的k个数(Randomized-Select方法)

/* *寻找最小的k个数 *题目描述:5.查找最小的k个元素 *题目:输入n个整数,输出其中最小的k个。 *例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。...

Selector select方法阻塞register的解决方法

Selector select方法阻塞register的解决方法

Jsoup中select方法详解

问题 采用CSS或类似jquery 选择器(selector)语法来处理HTML文档中的数据。 方法 利用方法:Element.select(String selector)...

JAVA中基于json串进行sql语句拼接实现select方法

接上次groovy中利用解析json串进行sql语句拼接继而实现select方法后,本次我们利用JAVA来实现这一功能。 首先老规矩,构造select方法函数,由于select是需要查询出结果...

寻找最小的k个数(Select方法)

/* *寻找最小的k个数 *题目描述:5.查找最小的k个元素 *题目:输入n个整数,输出其中最小的k个。 *例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。...

linux网络编程之socket(十一):套接字I/O超时设置方法和用select实现超时

一、使用alarm 函数设置超时  C++ Code  1 2 3 4 5 6 7 8 9 10 11 12 13 ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)