- 论坛徽章:
- 0
|
本帖最后由 wander__漫游世界 于 2014-09-04 19:43 编辑
学习select实现单线程实现并发,在网上找到两种版本。
一种能够实现并发通信,一种只有一个客户段能够通信,十分不解。下面上源码,求帮忙分析一下。
第一种能实现并发:- /*
- Thu Sep 4,4:12PM,2014
- @wander
- email:czpwander@gmail.com
- process: select socket server
- ps:单进程用select实现并发socket
- 网上有几种不同的实现方式,本程序是通过主进程实现监听socket,然后用select实现连接socket
- select 程序中是每次有一个新连接,然后将连接描述符添加到select描述符中,也就是一个一个添加。
- * */
- #include <stdio.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <string.h>
- #include <netinet/in.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <sys/select.h>
- #include <sys/time.h>
- #define LEN 1024
- #define PORT 60606
- #define BACKLOG 2
- struct client{
- int fd;
- struct sockaddr_in cli;
- };
- int main(void)
- {
- struct client cl[FD_SETSIZE];//客户端数组
- int connfd;
- int i;
- int maxfd,sockfd;
- int maxi = -1;
- int nready;
- char buf[LEN];// 接收发送socket buf
- int listenfd = socket(AF_INET,SOCK_STREAM,0);//创建监听socket
- if(listenfd < 0){
- perror("socket error\n");
- exit(-1);
- }
- int opt = SO_REUSEADDR;
- setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int));//设置解绑地址
- struct sockaddr_in ser;
- socklen_t ser_len = sizeof(ser);
- ser.sin_family = AF_INET;
- ser.sin_port = htons(PORT);
- ser.sin_addr.s_addr = htonl(INADDR_ANY);
-
- int ret = bind(listenfd,(struct sockaddr*)&ser,ser_len);//bind
- if(ret < 0){
- perror("bind error\n");
- exit(-1);
- }
-
- ret = listen(listenfd,BACKLOG); //listen
- if(ret < 0){
- perror("listen error\n");
- exit(-1);
- }
-
- //select
- maxfd = listenfd;
- for(i = 0;i < FD_SETSIZE;i ++){
- cl[i].fd = -1;
- }
- fd_set read_fds;
- fd_set r_fds;
- FD_ZERO(&read_fds);
- FD_ZERO(&r_fds);
- FD_SET(listenfd,&read_fds);
- while(1){
- memset(buf,0,LEN);
- struct sockaddr_in addr;
- r_fds = read_fds;//将select描述符集,赋值给r_fds
- socklen_t addr_len = sizeof(addr);
- bzero(&addr,addr_len);
- nready = select(maxfd+1,&r_fds,NULL,NULL,NULL);// select
- if(ret < 0){
- perror("select error\n");
- exit(-1);
- }
- if(FD_ISSET(listenfd,&r_fds)){// 判断是否有监听socket
- printf("get new connect\n");
- connfd = accept(listenfd,(struct sockaddr *)&addr,&addr_len);// accept socket
- if(connfd < 0){
- perror("accept error\n");
- exit(-1);
- }
- printf("accept ok\n");
-
- //将得到客户端地址 连接socketfd
- for(i = 0;i < FD_SETSIZE;i ++){
- if(cl[i].fd < 0){
- cl[i].fd = connfd;
- cl[i].cli = addr;
- printf("got connect from %s\n",inet_ntoa(cl[i].cli.sin_addr));
- //printf("got connect from client %d\n",i);
- break;
- }
- }
- if(i == FD_SETSIZE){// 连接达到最大值
- printf("too many client connect\n");
- continue;
- }
- FD_SET(connfd,&read_fds);//将连接sockefd添加到select描述符集中
- if(connfd > maxfd)// 判断最大
- maxfd = connfd;
- if(i > maxi){// 判断最大连接数
- maxi = i;
- printf("maxi:%d\n",maxi);
- }
- if(--nready <= 0)
- continue;//如果没有连接,就继续循环
- }
- for(i = 0;i <= maxi;i ++){// 判断是否有数据发送
- if((sockfd = cl[i].fd) < 0) //如果小于0,表示没有客户端连接
- continue;
- if(FD_ISSET(sockfd,&r_fds)){
- printf("get the data\n");
- int r_size = recv(sockfd,buf,LEN,0);//接收数据
- if(r_size == 0){
- close(sockfd);
- printf("close the %d client\n",i);
- }
- else if(r_size > 0){
- printf("the client %d:",i);
- printf("%s \n",buf);
- }
- if(--nready <= 0)
- break;
- }
- }
- }
-
- close(connfd);
- close(listenfd);
- }
复制代码 第二种,网上很多是第二种,但是能够建立连接,但是不能实现并发通信- /* 实现功能:通过select处理多个socket
- * 监听一个端口,监听到有链接时,添加到select的w.
- */
- //#include "select.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/socket.h>
- #include <sys/select.h>
- #include <sys/time.h>
- #include <netinet/in.h>
- #include <string.h>
- typedef struct _CLIENT{
- int fd;
- struct sockaddr_in addr; /* client's address information */
- } CLIENT;
- #define MYPORT 60606
- //最多处理的connect
- #define BACKLOG 2
- //最多处理的connect
- CLIENT client[BACKLOG];
- //当前的连接数
- int currentClient = 0;
- //数据接受 buf
- #define REVLEN 10
- char recvBuf[REVLEN];
- //显示当前的connection
- void showClient();
- int main()
- {
- int i, ret, sinSize;
- int recvLen = 0;
- fd_set readfds, writefds;
- int sockListen, sockSvr, sockMax;
- struct timeval timeout;
- struct sockaddr_in server_addr;
- struct sockaddr_in client_addr;
- //将客户端端描述符置1
- for(i=0; i<BACKLOG; i++)
- {
- client[i].fd = -1;
- }
- //socket
- if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- printf("socket error\n");
- return -1;
- }
- int opt = SO_REUSEADDR;
- setsockopt(sockListen,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int));
- bzero(&server_addr, sizeof(server_addr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(MYPORT);
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- //bind
- if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
- {
- printf("bind error\n");
- return -1;
- }
- //listen
- if(listen(sockListen, 5) < 0)
- {
- printf("listen error\n");
- return -1;
- }
- for(i=0; i<BACKLOG; i++)
- {
- client[i].fd = -1;
- }
- //select
- while(1)
- {
- FD_ZERO(&readfds);
- FD_SET(sockListen, &readfds);
- sockMax = sockListen;
-
- //加入client
- for(i=0; i<BACKLOG; i++)
- {
- if(client[i].fd >0)
- {
- FD_SET(client[i].fd, &readfds);
- if(sockMax<client[i].fd)
- sockMax = client[i].fd;
- }
- }
-
- timeout.tv_sec=10;
- timeout.tv_usec=0;
- //select
- ret = select((int)sockMax+1, &readfds, NULL, NULL, &timeout);
- if(ret < 0)
- {
- printf("select error\n");
- break;
- }
- else if(ret == 0)
- {
- printf("timeout ...\n");
- continue;
- }
- //printf("test111\n");
-
- //读取数据
- for(i=0; i<BACKLOG; i++)
- {
- if(client[i].fd>0 && FD_ISSET(client[i].fd, &readfds))
- {
- if(recvLen != REVLEN)
- {
- while(1)
- {
- //recv数据
- ret = recv(client[i].fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0);
- if(ret == 0)
- {
- client[i].fd = -1;
- recvLen = 0;
- break;
- }
- else if(ret < 0)
- {
- client[i].fd = -1;
- recvLen = 0;
- break;
- }
- //数据接受正常
- recvLen = recvLen+ret;
- if(recvLen<REVLEN)
- {
- continue;
- }
- else
- {
- //数据接受完毕
- printf("%s, buf = %s\n", inet_ntoa(client[i].addr.sin_addr) , recvBuf);
- //close(client[i].fd);
- //client[i].fd = -1;
- recvLen = 0;
- break;
- }
- }
- }
- }
- }
-
- //如果可读
- if(FD_ISSET(sockListen, &readfds))
- {
- printf("isset\n");
- sockSvr = accept(sockListen, NULL, NULL);//(struct sockaddr*)&client_addr
-
- if(sockSvr == -1)
- {
- printf("accpet error\n");
- }
- else
- {
- currentClient++;
- }
-
- for(i=0; i<BACKLOG; i++)
- {
- if(client[i].fd < 0)
- {
- client[i].fd = sockSvr;
- client[i].addr = client_addr;
- printf("You got a connection from %s \n",inet_ntoa(client[i].addr.sin_addr) );
- break;
- }
- }
- //close(sockListen);
- }
- }
- printf("test\n");
- return 0;
- }
- //显示当前的connection
- void showClient()
- {
- int i;
- printf("client count = %d\n", currentClient);
- for(i=0; i<BACKLOG; i++)
- {
- printf("[%d] = %d", i, client[i].fd);
- }
- printf("\n");
- }
复制代码 |
|