server:
未处理点:
1)pollfd 数组,应该设置一个有效总数,当fd最大有效索引值> 有效总数=某个比较值,那么应该执行数据压缩.
2)socket的有效超时是设定阻塞的.有没有方法.设置一个socket.的有效时?超过多少时间,无事件发生就关闭?还是需要自己处理.那么就应该自己多加一个值来记录每个socket的非活跃时间了.
#include <iostream> #include <sys/socket.h>//{socket_type.h}:socket,AF_INET,SOCK_STREAM,PF_INET #include <netdb.h>//{<netinet/in.h>}:IPPROTO_TCP #include <sys/errno.h> #include <string.h> #include <stdio.h>//perror #include <fcntl.h> #include <unistd.h>//close. #include <time.h> #include <arpa/inet.h>//INET_PTON #include <chrono> #include <vector> #include <algorithm> #include <poll.h> using namespace std; const int MAXLINE=1024*4; const int MAXFD=100; typedef struct sockaddr_in SA; string g_cmd; void Accpetthread(int serverFD); void threadProcess(int serverTempFD); int main() { //socket->addr->bind->listen->accept(read ,write) int serverFD; int intflag; g_cmd=""; SA serverAddr; bzero(&serverAddr,sizeof(serverAddr)); serverFD=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); if(serverFD==-1) { perror("create()"); return -1; } //serverAddr.sin_addr.s_addr=htonl(INADDR_ANY); inet_pton(AF_INET,"127.0.0.1",&serverAddr.sin_addr); serverAddr.sin_family=AF_INET; serverAddr.sin_port=htons(3013); //serverAddr.sin_zero?? intflag=bind(serverFD,(sockaddr*)&serverAddr,sizeof(sockaddr)); if(intflag==-1) { perror("bind()"); return -1; } listen(serverFD,10);//max queue? string cmd; cout<<"exist:input 88"<<endl; //stdin->cmd .socket->read&write. socket -> accept. //serverfd,stdin. //tempfd. //struct pollfd. poll() // int poll(struct pollfd *fds, nfds_t nfds, int timeout); // // #define _GNU_SOURCE /* See feature_test_macros(7) */ // #include <signal.h> // #include <poll.h> struct pollfd pollfdArray[MAXFD]; pollfdArray[0].fd=STDIN_FILENO; pollfdArray[0].events=POLLIN;//标准输入数据不是普通数据...... pollfdArray[0].revents=0; pollfdArray[1].fd=serverFD; pollfdArray[1].events=POLLRDNORM;//标准输入数据不是普通数据...... pollfdArray[1].revents=0; int fdMAXIndex=1; for(int i=2;i<MAXFD;++i) { pollfdArray[i].fd=-1; } while(true) { int pollStatus= poll(pollfdArray,fdMAXIndex+1,-1); if(pollStatus<0) { perror("poll()"); } else if(pollStatus==0) { cout<<"no events. why program be here?"<<endl; } else { if(pollfdArray[1].revents==POLLRDNORM) { pollfdArray[1].revents=0; int tempServerFD=accept(pollfdArray[1].fd,0,0);//-1或非负整数 if(tempServerFD==-1) { perror("accept()"); } for(int i=2;i<MAXFD;++i) { if(pollfdArray[i].fd==-1) { pollfdArray[i].fd=tempServerFD; pollfdArray[i].events=POLLRDNORM; fdMAXIndex=fdMAXIndex>i?fdMAXIndex:i; break;// } } if(--pollStatus<=0) { continue; } } for(int i=2;i<=fdMAXIndex&&pollStatus>0 ;++i) { if(pollfdArray[i].fd!=-1) { if(pollfdArray[i].revents==POLLRDNORM) { char readbuf[MAXLINE]; bzero(readbuf,MAXLINE); int sizeread= read(pollfdArray[i].fd,readbuf,MAXLINE-1); if(sizeread==-1)//-1到底是个什么状态?是彻底不能连接还是可以重试? { perror("read()"); close(pollfdArray[i].fd); pollfdArray[i].fd=-1; } else if(sizeread==0) { close(pollfdArray[i].fd); pollfdArray[i].fd=-1; } else { readbuf[sizeread]=‘\0‘;//以免溢出,插入结束符号. char writebuff[MAXLINE+10]; //snprintf如果格式化后的字符串长度 >= size,则只将其中的(size-1)个字符复制到str中,并给其后添加一个字符串结束符(‘\0‘) snprintf(writebuff,MAXLINE+10-1,"%s:%d\n",readbuf,strlen(readbuf)); cout<<writebuff<<flush; write(pollfdArray[i].fd,writebuff,strlen(writebuff)); } --pollStatus; } } } if(pollfdArray[0].revents==POLLIN) { pollfdArray[0].revents=0;//需要重设返回值不? cin>>cmd; if(cmd=="88") { //close all sockets. close(serverFD); break; } } } } // // while(true) // { // // if(FD_ISSET(STDIN_FILENO,&fdset)) // { // cin>>cmd; // if(cmd=="88") // { // close(serverFD); // break; // } // } // // if(FD_ISSET(serverFD,&fdset)) // { // //accept.& save it to array. // int serverTempFD=accept(serverFD,0,0); // if(serverTempFD==-1) // { // perror("accept"); // } // else // { // fdArrays.push_back(serverTempFD); // } // } // // // for(int tempfdid: fdArrays) // { // if(FD_ISSET(tempfdid,&fdset)) // { // char readbuf[MAXLINE]; // bzero(readbuf,MAXLINE); // int sizeread= read(tempfdid,readbuf,MAXLINE-1); // if(sizeread==-1)//-1到底是个什么状态?是彻底不能连接还是可以重试? // { // perror("read"); // fdArrays.erase(find(fdArrays.begin(),fdArrays.end(),tempfdid)); // close(tempfdid); // break; // } // else if(sizeread==0)//peer close or shutdown wr. // { // fdArrays.erase(find(fdArrays.begin(),fdArrays.end(),tempfdid)); // close(tempfdid); // break; // } // else // { // readbuf[sizeread]=‘\0‘;//以免溢出,插入结束符号. // char writebuff[MAXLINE+10]; // //snprintf如果格式化后的字符串长度 >= size,则只将其中的(size-1)个字符复制到str中,并给其后添加一个字符串结束符(‘\0‘) // snprintf(writebuff,MAXLINE+10-1,"%s:%d\n",readbuf,strlen(readbuf)); // cout<<writebuff<<flush; // write(tempfdid,writebuff,strlen(writebuff)); // } // } // } // } return 0; }
client:
#include <iostream> #include <sys/socket.h>//{socket_type.h}:socket,AF_INET,SOCK_STREAM,PF_INET #include <netdb.h>//{<netinet/in.h>}:IPPROTO_TCP #include <sys/errno.h> #include <string.h> #include <stdio.h>//perror,fgets #include <fcntl.h> #include <unistd.h>//close. #include <time.h> #include <netinet/in.h> #include <arpa/inet.h>//INET_PTON #include <string> const int MAXLINE=1024*4; using namespace std; int main() { //socket->connect->read. int socketClientFD; int statusFlag; socketClientFD=socket(PF_INET,SOCK_STREAM,IPPROTO_IP); if(socketClientFD==-1) { perror("socket()"); return -1; } struct sockaddr_in serverAddr; bzero(&serverAddr,sizeof(serverAddr)); serverAddr.sin_family=AF_INET; inet_pton(AF_INET,"127.0.0.1",&serverAddr.sin_addr); //printf("%0x,%0x,%0x,%0x",((char*)&serverAddr.sin_addr)[0],((char*)&serverAddr.sin_addr)[1],((char*)&serverAddr.sin_addr)[2],((char*)&serverAddr.sin_addr)[3]); serverAddr.sin_port=htons(3013); statusFlag=connect(socketClientFD,(sockaddr*)&serverAddr,sizeof(serverAddr)); if(statusFlag==-1) { perror("connect()"); return -1; } char writeChar[MAXLINE]; char buff[MAXLINE]; fd_set fdset;//定义描述符集。 FD_ZERO(&fdset);//初始化描述符集。 int endflag=0; while(true) { //1)如果没有会触发很多次shutdown(socketClientFD,SHUT_WR);。,并且导致服务端,read 的时候会收到-1. //这样直接就关闭connect。客户端可能读不到任何数据。 //2)为什么每次都要重新设置? if(endflag==0) { FD_SET(STDIN_FILENO,&fdset);//打开标准输入bit位。 } else { FD_CLR(STDIN_FILENO,&fdset);//与其后面取消。还不如根绝标志这里设置。这样还统一一点。代码更清晰. } FD_SET(socketClientFD,&fdset);//打开客户socket bit位。 int maxCheckFDCount=socketClientFD>STDIN_FILENO?socketClientFD+1:STDIN_FILENO+1;//只有2个描述符,肯定是除标准外的那个+1. select(maxCheckFDCount,&fdset,0,0,0);//只关心接收描述符。 if(FD_ISSET(STDIN_FILENO,&fdset)) { //cin.getline(writeChar,MAXLINE); bzero(writeChar,MAXLINE); cout<<"stdin fire"<<endl; int n=read(STDIN_FILENO,writeChar,MAXLINE); if(n==0) { cout<<"wirte over"<<endl; shutdown(socketClientFD,SHUT_WR); endflag=1; //close(socketClientFD); } else { statusFlag= write(socketClientFD,writeChar,strlen(writeChar));//写的时候只发送字符。不发送结束符。所以用strlen. if(statusFlag==-1) { perror("write()"); return -1; } } } if(FD_ISSET(socketClientFD,&fdset)) { bzero(buff,MAXLINE); statusFlag=read(socketClientFD,buff,MAXLINE-1); cout<<"start read"<<endl; if(statusFlag==0)//非正常关闭。因为这个cs模式下,服务端是被动关闭。程序是不可能得到0的。只有客户端close后才会由内核得到0. { cout<<"server close."<<endl; //close(socketClientFD);//到这里关闭。 break; } else if(statusFlag==-1) { perror("read()"); return -1; } else { buff[statusFlag]=‘\0‘; cout<<buff<<flush; } } } return 0; }
socket api- c/s模式:全双工 ;IO模式:同步阻塞,poll,多路复用。
原文:http://www.cnblogs.com/lsfv/p/6362441.html