目录 nc 127.0.0.1 port
01_socket_client.cc
01_socket_server.cc
02_select_client.cc
02_select_server.cc
03_poll_server.cc
04_epoll_server.cc
01_socket_client.cc
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <error.h>
#include <error.h>#include <iostream>
#include <string>using std::cout;
using std::endl;
using std::string;int main(int argc,char** argv)
{//socket-->listenfdint listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){error(1,errno,"socket");}//sockaddr_in --> connectstruct sockaddr_in seraddr;memset(&seraddr,0,sizeof(seraddr));seraddr.sin_family=AF_INET;seraddr.sin_port=htons(atoi(argv[2]));//portseraddr.sin_addr.s_addr=inet_addr(argv[1]);//ipint ret=connect(listenfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(ret<0){error(1,errno,"connect");}//三次握手建立成功while(1){cout<<"propose send message to server"<<endl;string line;getline(std::cin,line);ret=send(listenfd,line.data(),line.size(),0);if(ret<0){cout<<"send error"<<endl;}else if(ret==0){cout<<"ret==0"<<endl;}else{cout<<"send sucessfully"<<endl;}char buff[128]={0};ret=recv(listenfd,buff,sizeof(buff),0);if(ret<0){cout<<"recv error"<<endl;}else if(ret==0){cout<<"ret==0"<<endl;}else{cout<<"recv sucessfully>>>"<<buff<<endl;}}close(listenfd);return 0;
}
01_socket_server.cc
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <error.h>
#include <error.h>#include <iostream>
#include <string>using std::cout;
using std::endl;
using std::string;int main(int argc,char** argv)
{int listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){error(1,errno,"socket");}//port ip 复用int opt=1;int retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(opt));if(retval<0){error(1,errno,"setscockopt");}int opt2=1;retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt2,sizeof(opt2));if(retval<0){error(1,errno,"setscockopt2");}//bindstruct sockaddr_in seraddr;memset(&seraddr,0,sizeof(seraddr));seraddr.sin_addr.s_addr=inet_addr(argv[1]);seraddr.sin_port=htons(atoi(argv[2]));seraddr.sin_family=AF_INET;int ret=bind(listenfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(ret<0){error(1,errno,"bind");}//监听ret=listen(listenfd,128);if(ret<0){error(1,errno,"listen");}cout<<"server is listen"<<endl;//从listenfd队列中取下一个peerfdint connfd=accept(listenfd,nullptr,nullptr);if(connfd<0){error(1,errno,"accept");}//三次握手建立成功while(1){char buff[128]={0};ret=recv(connfd,buff,sizeof(buff),0);if(ret<0){cout<<"recv error"<<endl;}else if(ret==0){cout<<"ret==0"<<endl;}else{cout<<"recv sucessfully>>>"<<buff<<endl;}cout<<"propose send message to client"<<endl;string line;getline(std::cin,line);int ret1=send(connfd,line.data(),line.size(),0);if(ret1<0){cout<<"send error"<<endl;}else if(ret1==0){cout<<"ret1==0"<<endl;}else{cout<<"send sucessfully"<<endl;}}close(listenfd);close(connfd);return 0;
}
02_select_client.cc
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <error.h>
#include <error.h>#include <iostream>
#include <string>#define SERV_IP "192.168.235.128"
#define SERV_PORT 8000using std::cout;
using std::endl;
using std::string;int main(int argc,char** argv)
{//socket-->listenfdint listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){error(1,errno,"socket");}//sockaddr_in --> connectstruct sockaddr_in seraddr;memset(&seraddr,0,sizeof(seraddr));seraddr.sin_family=AF_INET;seraddr.sin_port=htons(SERV_PORT);//port/* seraddr.sin_addr.s_addr=inet_addr(SERV_IP);//ip *//* inet_pton(listenfd, SERV_IP, &serv_addr.sin_addr.s_addr); */seraddr.sin_addr.s_addr=htonl(INADDR_ANY);//服务器绑定所有可用接口int ret=connect(listenfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(ret<0){error(1,errno,"connect");}//三次握手建立成功char buff[BUFSIZ];//标准io操作的缓冲区大小int nByte;while(1){fgets(buff,sizeof(buff),stdin);//helloc-->hello\n\0write(listenfd,buff,strlen(buff));//buff有效长度//buff的内容写入listenfd(套接字本质文件描述符)nByte=read(listenfd,buff,sizeof(buff));//读取服务器的响应,nByte实际读取的字节数write(STDOUT_FILENO,buff,nByte);//写到stdout}close(listenfd);return 0;
}
02_select_server.cc
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <error.h>
#include <error.h>
#include <sys/select.h>
#include <sys/time.h>#include <iostream>
#include <string>#define SERV_PORT 8000using std::cout;
using std::endl;
using std::string;int main(int argc,char** argv)
{int cnt ;//debugint connfd,sockfd;int listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){error(1,errno,"socket");}//port ip 复用int opt=1;int retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(opt));if(retval<0){error(1,errno,"setscockopt");}int opt2=1;retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt2,sizeof(opt2));if(retval<0){error(1,errno,"setscockopt2");}//bindstruct sockaddr_in seraddr;bzero(&seraddr,sizeof(seraddr));/* memset(&seraddr,0,sizeof(seraddr)); */seraddr.sin_addr.s_addr=htonl(INADDR_ANY);seraddr.sin_port=htons(SERV_PORT);seraddr.sin_family=AF_INET;int ret=bind(listenfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(ret<0){error(1,errno,"bind");}//监听ret=listen(listenfd,128);if(ret<0){error(1,errno,"listen");}cout<<"server is listen"<<endl;//三次握手建立成功char buff[BUFSIZ],str[BUFSIZ];int maxfd=listenfd;int maxi=-1;fd_set rset,allset;int client[FD_SETSIZE];//多1024,可以监视的最大文件描述符数量//定义在/usr/include/linux/posix_types.hfor(int i=0;i<FD_SETSIZE;++i){client[i]=-1;}FD_ZERO(&allset);FD_SET(listenfd,&allset);while(1){rset=allset;int nready=select(maxfd+1,&rset,NULL,NULL,NULL);//nready就绪的描述符数量if(nready<0){error(1,errno,"select");}//01,监听到listenfd 新的链接进来if(FD_ISSET(listenfd,&rset)){struct sockaddr_in clie_addr;socklen_t clie_addr_len=sizeof(clie_addr);//新连接的套接字connfd=accept(listenfd,(struct sockaddr*)&clie_addr,&clie_addr_len);if(connfd==-1){error(1,errno,"accept");}printf("receive from %s : %d\n",inet_ntop(AF_FILE,&clie_addr.sin_addr,str,sizeof(str)),ntohs(clie_addr.sin_port));//三次握手成功int i;for(i=0;i<FD_SETSIZE;++i){if(client[i]<0){client[i]=connfd;break;//加入监听数组} }//==============================cout<<cnt++<<" "<<i<<endl;if(i==FD_SETSIZE){fputs("too much client\n",stderr);exit(1);}FD_SET(connfd,&allset);//添加新连接//更新maxi,maxfdif(connfd>maxfd){maxfd=connfd;}if(i>maxi){maxi=i;}//如果nready=1.继续while循环,不用走下面的for循环if(--nready==0){continue;}}//02遍历client数组,元素为正,被监听到//是老连接,可以进行数据发送接受for(int i=0;i<=maxi;++i){//caution:i<=maxiif((sockfd=client[i])<0){continue;}
//==============================cout<<cnt++<<" "<<sockfd<<endl;if(FD_ISSET(sockfd,&rset)){int nByte=read(sockfd,buff,sizeof(buff));if(nByte==0){//数据读完了,(缓冲区没有数据//连接要断开了close(sockfd);cout<<"client "<<sockfd<<" closed connection\n"<<endl;FD_CLR(sockfd,&allset);client[i]=-1;}else if(nByte>0){for(int j=0;j<nByte;++j){buff[j]=toupper(buff[j]);//a->A}write(sockfd,buff,nByte);write(STDOUT_FILENO,buff,nByte);}if(--nready==0){break;}}}}close(listenfd);close(connfd);return 0;
}
03_poll_server.cc
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <error.h>
#include <errno.h>
#include <poll.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>#include <iostream>
#include <string>#define OPEN_MAX 1024
/* #define SERV_IP "192.168.235.128" */
#define SERV_IP "127.0.0.1"
#define SERV_PORT 7888using std::cout;
using std::endl;
using std::string;/* struct pollfd */
/* { */
/* int fd; //要监听的文件描述符 */
/* short events; //待监听的文件描述符的事件 POLLIN/POLLOUT/POLLERR */
/* short revents; //revents & POLLIN */
/* }; */int main(int argc,char** argv)
{int cnt ;//debugint connfd,sockfd;int listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){error(1,errno,"socket");}//port ip 复用int opt=1;int retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(opt));if(retval<0){error(1,errno,"setscockopt");}int opt2=1;retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt2,sizeof(opt2));if(retval<0){error(1,errno,"setscockopt2");}//bindstruct sockaddr_in seraddr;bzero(&seraddr,sizeof(seraddr));/* memset(&seraddr,0,sizeof(seraddr)); */seraddr.sin_addr.s_addr=htonl(INADDR_ANY);/* seraddr.sin_addr.s_addr=inet_pton( *//* listenfd, SERV_IP, &seraddr.sin_addr.s_addr); */seraddr.sin_port=htons(SERV_PORT);seraddr.sin_family=AF_INET;int ret=bind(listenfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(ret<0){error(1,errno,"bind");}//监听ret=listen(listenfd,128);if(ret<0){error(1,errno,"listen");}cout<<"server is listen"<<endl;//三次握手建立成功char buff[BUFSIZ],str[INET_ADDRSTRLEN];//IPV4地址的字符串表示形式的最大长度int maxi=0;struct pollfd client[OPEN_MAX];//FOPEN_MAX:一个程序可以同时打开的最大文件流数量//poll类型,listenfd加入监听client[0].fd=listenfd;client[0].events=POLLIN;for(int i=1;i<OPEN_MAX;++i){//i=0,会把listenfd删掉,注意初始化顺序client[i].fd=-1;}while(1){int nready=poll(client,maxi+1,-1);if(nready<0){error(1,errno,"select");}
//==============================cout<<cnt++<<" "<<client[0].fd<<endl;//01,监听到listenfd 新的链接进来if(client[0].revents & POLLIN){struct sockaddr_in clie_addr;socklen_t clie_addr_len=sizeof(clie_addr);//新连接的套接字connfd=accept(listenfd,(struct sockaddr*)&clie_addr,&clie_addr_len);if(connfd==-1){error(1,errno,"accept");}printf("receive from %s : %d\n",inet_ntop(AF_FILE,&clie_addr.sin_addr,str,sizeof(str)),ntohs(clie_addr.sin_port));//三次握手成功int i;for(i=1;i<OPEN_MAX;++i){if(client[i].fd<0){client[i].fd=connfd;break;//加入监听数组} }client[i].events=POLLIN;//设置要监听的类型if(i==OPEN_MAX){fputs("too much client\n",stderr);exit(1);}//更新maxi,fd有新增if(i>maxi){maxi=i;}//如果nready=1.继续while循环,不用走下面的for循环if(--nready==0){continue;}}//02遍历client数组,元素为正,被监听到//是老连接,可以进行数据发送接受for(int i=0;i<=maxi;++i){//caution:i<=maxiif((sockfd=client[i].fd)<0){continue;}//老连接上有数据if(client[i].revents & POLLIN){int nByte=read(sockfd,buff,sizeof(buff));if(nByte<0){if(errno==ECONNRESET){//客户端被强制关闭cout<<"client ["<<i<<"] abort connect"<<endl;close(sockfd);client[i].fd=-1;}else{perror("read nByte=0 error");}}else if(nByte>0){for(int j=0;j<nByte;++j){buff[j]=toupper(buff[j]);//a->A}write(sockfd,buff,nByte);write(STDOUT_FILENO,buff,nByte);}else{close(sockfd);cout<<"client ["<<i<<"] closed connection"<<endl;client[i].fd=-1;}if(--nready==0){break;}}}}close(listenfd);close(connfd);return 0;
}
04_epoll_server.cc
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <error.h>
#include <errno.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>#include <iostream>
#include <string>#define OPEN_MAX 1024
/* #define SERV_IP "192.168.235.128" */
#define SERV_IP "127.0.0.1"
#define SERV_PORT 6888using std::cout;
using std::endl;
using std::string;/* typedef union epoll_data { */
/* void *ptr; */
/* int fd; */
/* uint32_t u32; */
/* uint64_t u64; */
/* } epoll_data_t; *//* struct epoll_event { */
/* uint32_t events; //EPOLLIN/EPOLLOUT/EPOLLERR */
/* epoll_data_t data; /1* User data variable *1/ */
/* }; */int main(int argc,char** argv)
{int cnt ;//debugint connfd,sockfd;int listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){error(1,errno,"socket");}//port ip 复用int opt=1;int retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(opt));if(retval<0){error(1,errno,"setscockopt");}int opt2=1;retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt2,sizeof(opt2));if(retval<0){error(1,errno,"setscockopt2");}//bindstruct sockaddr_in seraddr;bzero(&seraddr,sizeof(seraddr));seraddr.sin_addr.s_addr=htonl(INADDR_ANY);/* seraddr.sin_addr.s_addr=inet_pton( *//* listenfd, SERV_IP, &seraddr.sin_addr.s_addr); */seraddr.sin_port=htons(SERV_PORT);seraddr.sin_family=AF_INET;int ret=bind(listenfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(ret<0){error(1,errno,"bind");}//监听ret=listen(listenfd,128);if(ret<0){error(1,errno,"listen");}cout<<"server is listen"<<endl;char buff[BUFSIZ],str[INET_ADDRSTRLEN];//IPV4地址的字符串表示形式的最大长度//创建红黑树的根节点(红黑树+就绪链表)int epfd=epoll_create(OPEN_MAX);/* int epfd=epoll_create1(1); */if(epfd==-1){error(1,errno,"epoll_create1");}//赋值evt,listenfd加入监听struct epoll_event evt,ep[OPEN_MAX];evt.events=EPOLLIN;evt.data.fd=listenfd;ret=epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&evt);if(ret<0){error(1,errno,"epoll_ctl(add) listenfd");}while(1){int nready=epoll_wait(epfd,ep,OPEN_MAX,-1);if(nready<0){error(1,errno,"select");}
//==============================
cout<<cnt++<<" "<<ep[0].data.fd<<endl;
//递增的ep[0].data.fd,记录的是接收到的事件的数量
//这个上下文中是用来输出当前处理的事件的文件描述符,
//可能会是新连接的文件描述符,所以会看起来是递增的 //02遍历nreadyfor(int i=0;i<nready;++i){//异常处理if(!(ep[i].events & EPOLLIN)){continue;}//监听到listenfd,新连接//(监听到连接事件)if(ep[i].data.fd == listenfd){struct sockaddr_in clie_addr;socklen_t clie_addr_len=sizeof(clie_addr);//新连接的套接字connfd=accept(listenfd,(struct sockaddr*)&clie_addr,&clie_addr_len);if(connfd==-1){error(1,errno,"accept");}printf("receive from %s : %d\n",inet_ntop(AF_FILE,&clie_addr.sin_addr,str,sizeof(str)),ntohs(clie_addr.sin_port));//三次握手成功//新连接加入监听evt.events=EPOLLIN;evt.data.fd=connfd;ret=epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&evt);if(ret<0){error(1,errno,"epoll_ctl(add) connfd");}}//不是连接事件--> 读写事件-->有消息else {sockfd=ep[i].data.fd;int nByte=read(sockfd,buff,sizeof(buff));//缓冲区空,即将断开if(nByte==0){ret=epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);if(ret<0){error(1,errno,"epoll_ctl(delete)");}close(sockfd);cout<<"client ["<<sockfd<<"] closed connecttion"<<endl;}//连接异常else if(nByte<0){perror("epoll_wait error");ret=epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);if(ret<0){error(1,errno,"epoll_ctl(delete)");}close(sockfd);}//正常通信else{for(int j=0;j<nByte;++j){buff[j]=toupper(buff[j]);//a->A}write(sockfd,buff,nByte);write(STDOUT_FILENO,buff,nByte);}}}}close(listenfd);close(connfd);return 0;
}