tcpserver.c服務器
int main(int argc, char**argv) { int listenfd = socket(AF_INET,SOCK_STREAM,0); struct sockaddr_in serv_addr, client_addr; socklen_t client_len = sizeof(client_addr); memset(&serv_addr,0,sizeof(serv_addr)); memset(&client_addr,0,sizeof(client_addr)); serv_addr.sin_addr.s_addr = INADDR_ANY; //綁定全部ip serv_addr.sin_family=AF_INET; serv_addr.sin_port = htons(PORT); int opt = 1; socklen_t optlen = sizeof(opt); //設置複用ip if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,optlen) < 0){ perror("setsockopt"); return 0; } //設置ip port if(bind(listenfd,(SA*)&serv_addr,sizeof(serv_addr)) < 0){ perror("bind"); return 0; } //BACKLOG = 10 if(listen(listenfd,BACKLOG) < 0){ perror("listen"); return 0; } //一些變量,下面會用到 int nready = 0,client[FD_SETSIZE] , maxfd = listenfd , connfd = 0,maxi = -1; // client 用於存儲 客戶描述符 for(int i = 0; i < FD_SETSIZE ; ++i) client[i] = -1; fd_set rset ,allset; FD_ZERO(&allset); //把監聽套接字先置位 FD_SET(listenfd,&allset); int clientfd = -1 , n = 0 , i = 0; char buf[BUFSIZ]; while(1){ //select 每次將修改rset,須要重置 rset = allset; nready = select(maxfd+1,&rset,NULL,NULL,NULL); printf("nread : %d \n" , nready); //可能被信號打斷 if(nready < 0){ perror("select"); continue; } //客戶連接 進來 if(FD_ISSET(listenfd,&rset)){ client_len = sizeof(client_addr); connfd = accept(listenfd,(SA*)&client_addr,&client_len); printf("a client : %d\n" , connfd); //找個位置放進去 for(i = 0; i < FD_SETSIZE; ++i){ if(client[i] < 0) { client[i] = connfd; break; } } //服務器已滿 if(FD_SETSIZE == i){ close(connfd); puts("server is full"); } else { //把客戶fd 放入監聽集合中 FD_SET(connfd,&allset); if(connfd > maxfd) maxfd = connfd; //client 索引 if( i > maxi) maxi = i; //若是數量爲0 則不須要往下繼續了 if(--nready == 0) continue; } } for(int i = 0 ; i <= maxi;++i){ if((clientfd = client[i]) <0 ) continue; //直到找到一個可讀的fd if(FD_ISSET(clientfd,&rset)){ printf("clientfd : %d is ready\n", clientfd); //若是對斷關閉了 if((n = read(clientfd,buf,BUFSIZ)) <= 0){ printf("clientfd : %d closed\n",clientfd); //清空當前fd 所存在的地方 close(clientfd); FD_CLR(clientfd,&allset); client[i] = -1; } else{ write(clientfd,buf,n); } if(--nready == 0) break; } } } return 0; }
tcpclient.c網絡
void str_echo(int sockfd); int max(int a, int b){ return a > b ? a : b; } int main(int argc, char**argv) { if(argc != 2){ puts("ip addr"); return 0; } int sockfd = socket(AF_INET,SOCK_STREAM,0); struct sockaddr_in sin; memset(&sin,0,sizeof(sin)); sin.sin_port = htons(PORT); sin.sin_family = AF_INET; //把字符串轉成網絡字節序 inet_pton(AF_INET,argv[1],&sin.sin_addr); connect(sockfd,(SA*)&sin,sizeof(sin)); str_echo(sockfd); return 0; } void str_echo(int sockfd){ int maxfd = sockfd; int eof = 0 , readn = 0 , fd_num = 0, n= 0; char buf[BUFSIZ]; fd_set rset; FD_ZERO(&rset); while(1) { //EOF ==》 CTRL+D if(0 == eof){ FD_SET(0,&rset); } //select 將修改rset ,每次重置 FD_SET(sockfd,&rset); maxfd = max(0,sockfd); fd_num = select(maxfd+1,&rset,NULL,NULL,NULL); printf("fd_num : %d\n" , fd_num); //若是是套接字可讀 if(FD_ISSET(sockfd,&rset)){ //服務器關閉 if((n=read(sockfd,buf,BUFSIZ)) <= 0){ if(eof == 1){ puts("server closed"); break; } else { puts("server ter"); break; } } buf[n] = 0; printf("recv from serv:%s\n" , buf); } //若是是輸入端可讀 if(FD_ISSET(0,&rset)){ //若是ctrl + d if((n = read(0,buf,BUFSIZ)) <= 0){ printf("client closing\n"); //先發送Fin , 等服務端close shutdown(sockfd,SHUT_WR); eof = 1; FD_CLR(0,&rset); continue; } write(sockfd,buf,n); } } }