select版的TCP通信
来源:互联网 发布:理光软件研究所业务 编辑:程序博客网 时间:2024/06/09 16:33
编写代码之前,大概先说一下利用select编写tcp的思路及select特点。
select系统调用是用来让程序监视多个文件句柄的状态变化的,程序会停在select这里等待,直到被监视的句柄有一个或者多个发生了状态改变。
select函数为:int select(int nfds,fd_set *readfds,fd_set* writefds,异常文件描述符,时间长度)//默认时间长度异常事件描述符一般都为NULL
在select中提出四个宏来处理描述数组的方式:(fd为文件描述符集set为描述数组)
FD_SET(fd,fd_set* set):用来设置set中fd位
FD_ISSET(fd,fd_set* set):用来测试set中额相关fd位是否为真
FD_ZERO(fd,fd_set* set):用来清除set的全部位
FD_CLR(fd_set*set):用来清除set中相关的fd的位
当然select的模型最终的特点如下:(1)select下可监控的文件描述符的个数取决于系统的大小
(2)每次检测到一个新的fd,都要手动的将fd添加到set中,并且使用一个数据结构arrar来保存select监控集中的set
(3)select模型必须在设了select前循环array
在大致了解了select的特点之后,现在就来说一说select 版的tcp的编写思路:
1:搭建好基本的tcp的框架,在服务器端编写-->生成套接字(starup),绑定端口(bind),监听(listen)模块,接受客户端访问(accept)模块
2.客户端实现连接请求模块(connect)
3.定义一个数组arrary,初始值为-1,然后把步骤1 中生成的监听套接字(listen_sock)添加到该数组
4.编写select函数监听来自客户端的请求,若监听到客户端连接,就会生成一个new_sock套接字,那么当然把这个套接字添加到数组arrary中。当下次遍历数组时得到的是new_sock套接字,那它就被作为数据传输套接字进行数据接收。
5.在步骤4的基础上读取客户端放在缓冲区的内容。
好啦!以上大致就是编写思路的说明了,下面贴出代码:
服务器端:server.c
#include<stdio.h>#include<stdlib.h>#include<errno.h>#include<sys/types.h>#include<sys/socket.h>#include<arpa/inet.h>#include<netinet/in.h>#include<unistd.h>#include<string.h>#define port 8080#define MAX_FD_NUM 20int array_fd[MAX_FD_NUM];//for watch fdint startup(){int sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket");exit(1);}struct sockaddr_in local;local.sin_family=AF_INET;local.sin_port=htons(port);local.sin_addr.s_addr=htonl(INADDR_ANY);if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0){perror("bind");exit(1);}if(listen(sock,5)<0){perror("listen");exit(1);}return sock;}int main(){int listen_sock=startup();struct sockaddr_in client; socklen_t len =sizeof(client);fd_set read_set;//READ int max_fd=listen_sock;//init arrayint i=0;for(;i<MAX_FD_NUM;i++){ array_fd[i]=-1;//set init key=-1}array_fd[0]=listen_sock;while(1){ FD_ZERO(&read_set);//empty read_set for(i=0;i<MAX_FD_NUM;i++) { if(array_fd[i]>0) { FD_SET(array_fd[i],&read_set);//set array_fd in red_set if(max_fd<array_fd[i]) { max_fd=array_fd[i];//get max_fd } } } switch(select(max_fd+1,&read_set,NULL,NULL,NULL)) {case 0://timeoutprintf("timeout...");break;case -1://errorperror("select"); break;default:for(i=0;i<MAX_FD_NUM;i++){if(array_fd<0){continue; }//new connectelse if(array_fd[i]==listen_sock && FD_ISSET(array_fd[i],&read_set)){int new_sock=accept(array_fd[i],(struct sockaddr*)&client,&len);if(new_sock<0){continue;}printf("get new connect: %d\n",new_sock);for(i=0;i<MAX_FD_NUM;i++){ if(array_fd[i]==-1) { array_fd[i]=new_sock; break; }} if(i==MAX_FD_NUM) { close(new_sock); }}else{for(i=1;i<MAX_FD_NUM;i++){if(array_fd[i]>0 && FD_ISSET(array_fd[i],&read_set)){char buf[1024];memset(buf,'\0',sizeof(buf));ssize_t _size=read(array_fd[i],buf,sizeof(buf)-1);if(_size<0){printf("read failed");close(array_fd[i]);}else if(_size==0){printf("client close...\n");close(array_fd[i]);}else{printf("client: %s\n",buf);}}}}}break; }}close(listen_sock);return 0;}
客户端:client.c
#include<stdio.h>#include<string.h>#include<sys/types.h>#include<sys/socket.h>#include<arpa/inet.h>#include<stdlib.h>#include<netinet/in.h>#include<errno.h>int main(){ int read_fd=0; int write_fd=1; int max_fd=0; fd_set read_set; fd_set write_set; int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(1); } struct sockaddr_in remote;remote.sin_family=AF_INET;remote.sin_port=htons(8080);remote.sin_addr.s_addr=inet_addr("192.168.198.128");//本机IPint new_sock=connect(sock,(struct sockaddr *)&remote,sizeof(remote));if(new_sock<0){perror("connect");exit(1);}if(sock >read_fd) max_fd=sock;elsemax_fd=read_fd; while(1) { FD_ZERO(&read_set);//empty FD_ZERO(&write_set); FD_SET(read_fd,&read_set);//set FD_SET(sock,&write_set);// switch(select(max_fd+1,&read_set,&write_set,NULL,NULL)) { case 0://timeout printf("timeout...\n"); break;case -1://error printf("there are bug\n"); printf("error...\n"); break;default://data ready { if(FD_ISSET(read_fd,&read_set))//judge { char buf[1024]; ssize_t _size=read(read_fd,buf,sizeof(buf)-1); if(_size>0) { buf[_size]='\0'; printf("echo:%s\n",buf); } if(FD_ISSET(sock,&write_set)) { //printf("write successful\n"); send(sock,buf,strlen(buf),0); // printf("%d\n",_size); } } } break; } }return 0;}
Makefie文件:
.PHONY:allall:server clientclient:client.cgcc -o $@ $^server:server.cgcc -o $@ $^.PHONY:cleanclean:rm -r server client
- select版的TCP通信
- 异步TCP通信-select
- VC6.0下select+多线程基于TCP的网络通信
- 简单的TCP-Select
- [转]Linux 下给类tcp 通信模式的实现。select 函数
- 基于select模型的tcp服务器---一个服务器如何与多个客户端进行通信?
- 利用tcp通信与select混用的通信模型中一方终止引发另一方死循环的解决方案
- C#的TCP通信
- ACE的TCP通信
- C#的TCP通信
- C#的TCP通信
- 简单的TCP通信
- python的tcp通信
- 简单的TCP通信
- SSL的TCP通信
- TCP通信的实现
- 简单的TCP通信
- TCP简单的通信
- Android异步线程,Looper, MessageQueue
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- FragmentTransaction与Fragment生命周期的关系
- 阿里百川 用户反馈(feedback) 与 (com.umeng.lib.xxxxx 及 和 alipaySDK-xxxxx) 冲突的问题。
- Git详解之二 Git基础
- select版的TCP通信
- continue VS break
- linux系统调用和库函数调用的区别
- UNPv2第八章:读写锁
- WebView开发中的常见问题
- SPI
- 蓝桥杯 埃及分数
- server 远程服务器登录及文件传输
- 搜索后再分页