客户端
// 三次握手主要是创建连接 // 四次挥手主要是释放资源 // I/O 复用 epoll模式 #include <iostream> #include
<arpa/inet.h> #include <unistd.h> #include <strings.h> // bzero() #include
<thread> //#include <sys/select.h> #include <sys/epoll.h> // epoll() #include
<linux/fs.h> // OPEN_MAX using namespace std; string name; void show_connect(int
fd) { // 获取本地地址和端口 struct sockaddr_in local_addr; socklen_t local_addr_len =
sizeof(local_addr); bzero(&local_addr,local_addr_len); // 清空 防止后面误用 getsockname(
fd,(struct sockaddr*)&local_addr,&local_addr_len); cout << "local " << inet_ntoa
(local_addr.sin_addr) << ":" << ntohs(local_addr.sin_port) << endl; // 获取远程地址和端口
struct sockaddr_in remote_addr; socklen_t remote_addr_len = sizeof(remote_addr);
bzero(&remote_addr,remote_addr_len); getpeername(fd,(struct sockaddr*)&
remote_addr,&remote_addr_len); cout << "remote " << inet_ntoa(remote_addr.
sin_addr) << ":" << ntohs(remote_addr.sin_port) << endl; } // ./clinet IP port
name int main(int argc,char* argv[]) { if(4!=argc) { cout << "Usage:" << argv[0]
<< " IP port name" << endl; return 1; } name = argv[3]; // 1.创建连接套接字 int connfd
= socket(AF_INET,SOCK_STREAM,0); if(-1 == connfd) { cout << "socket error" <<
endl; return 1; } // 2. 连接服务器 struct sockaddr_in remote_addr; // in是internet简写
remote_addr.sin_family = AF_INET; // 协议 sin是sockaddr_in的缩写 remote_addr.sin_addr.
s_addr= inet_addr(argv[1]); // IP地址 remote_addr.sin_port = htons(atoi(argv[2]));
// 端口号 小端转大端 if(-1==connect(connfd,(struct sockaddr*)&remote_addr,sizeof(
remote_addr))) { cout << "connect error" << endl; return 1; } else { cout <<
"connect success" << endl; cout << inet_ntoa(remote_addr.sin_addr) << ":" <<
ntohs(remote_addr.sin_port) << endl; show_connect(connfd); } // 创建epoll描述符 int
epollfd= epoll_create(2); // 注册事件 struct epoll_event evt; evt.data.fd =
STDIN_FILENO; evt.events = EPOLLIN; epoll_ctl(epollfd,EPOLL_CTL_ADD,STDIN_FILENO
,&evt); evt.data.fd = connfd; evt.events = EPOLLIN; epoll_ctl(epollfd,
EPOLL_CTL_ADD,connfd,&evt); bool stop = false; while(!stop) { int count = 2;
struct epoll_event revt[2]; int revt_count = epoll_wait(epollfd,revt,count,-1);
for(int i=0;i<revt_count;++i){ if(revt[i].data.fd == STDIN_FILENO && revt[i].
events& EPOLLIN){ // 3.发送信息 string message; getline(cin,message); message = name
+ ":" + message; write(connfd,message.c_str(),message.size()+1); }else if(revt[i
].data.fd == connfd && revt[i].events & EPOLLIN){ // 4.接收数据 char buffer[1024] =
{0}; int len = read(connfd,buffer,sizeof(buffer)); if(len == 0) { cout <<
"server exit" << endl; epoll_ctl(epollfd,EPOLL_CTL_DEL,connfd,revt+i); --count;
stop= true; break; } else { cout << buffer<< endl; } } } } close(epollfd); //
5. 关闭套接字 close(connfd); return 0; }
服务端
// 一服务器 -> 多客户端 // 三次握手主要是创建连接 // 四次挥手主要是释放资源 // I/O复用 epoll模式 #include
<iostream> #include <arpa/inet.h> #include <unistd.h> #include <strings.h> //
bzero() #include <pthread.h> #include <list> // remove() #include <thread> #
include <algorithm> // max_element() #include <sys/epoll.h> // epoll() #include
<linux/fs.h> // OPEN_MAX using namespace std; void show_connect(int fd) { //
获取本地地址和端口 struct sockaddr_in local_addr; socklen_t local_addr_len = sizeof(
local_addr); bzero(&local_addr,local_addr_len); // 清空 防止后面误用 getsockname(fd,(
struct sockaddr*)&local_addr,&local_addr_len); cout << "local " << inet_ntoa(
local_addr.sin_addr) << ":" << ntohs(local_addr.sin_port) << endl; // 获取远程地址和端口
struct sockaddr_in remote_addr; socklen_t remote_addr_len = sizeof(remote_addr);
bzero(&remote_addr,remote_addr_len); getpeername(fd,(struct sockaddr*)&
remote_addr,&remote_addr_len); cout << "remote " << inet_ntoa(remote_addr.
sin_addr) << ":" << ntohs(remote_addr.sin_port) << endl; } // ./server ip port
int main(int argc,char* argv[]) { if(3!=argc) { cout << "Usage:" << "输入 IP port"
<< endl; return 1; } // 1. 监听套接字 int listenfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == listenfd) { cout << "listen socket error" << endl; return 1; } //
为了避免端口被占用,想要再次使用同一个端口 // 设置端口重复利用(一般用在调试中) int flag = 1; setsockopt(listenfd,
SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag)); // 2. 绑定 struct sockaddr_in
local_addr; local_addr.sin_family = AF_INET; // IPv4协议 local_addr.sin_addr.
s_addr= inet_addr(argv[1]); // IP地址 local_addr.sin_port = htons(atoi(argv[2]));
// 端口号 if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr)))
{ //套接字和端口绑定 cout << "bind error" << endl; return 1; } else { cout << "bind
success" << endl; } // 3. 监听设置 if(-1==listen(listenfd,10)) { cout << "listen
error" << endl; return 1; } else { cout << "listen success" << endl; } int
epollfd= epoll_create(INR_OPEN_MAX); struct epoll_event evt; evt.data.fd =
STDIN_FILENO; evt.events = EPOLLIN; epoll_ctl(epollfd,EPOLL_CTL_ADD,STDIN_FILENO
,&evt); //监听标准输入 evt.data.fd = listenfd; epoll_ctl(epollfd,EPOLL_CTL_ADD,
listenfd,&evt); int count = 2; list<int> fds; while(true) { struct epoll_event
revt[count]; int revt_cnt = epoll_wait(epollfd,revt,count,-1); for(int i=0; i<
revt_cnt; ++i) { if(revt[i].data.fd == STDIN_FILENO && revt[i].events & EPOLLIN)
{ //如果事件是输入 并且文件描述符包括可读 string message; getline(cin,message); cin.clear(); //
清空输入出错 if(!message.empty()) { // 判断终端输入是否为空 message = "广告:" + message; for(auto
fd:fds) { write(fd,message.c_str(),message.size()+1); } } }else if(revt[i].data.
fd== listenfd && revt[i].events & EPOLLIN) { struct sockaddr_in remote_addr;
bzero(&remote_addr,sizeof(remote_addr)); // 清空 socklen_t remote_addr_len =
sizeof(remote_addr); int connfd = accept(listenfd,(struct sockaddr*)&remote_addr
,&remote_addr_len); //int connfd = accept(listenfd,NULL,NULL); if(-1 == connfd)
{ cout << "accept error" << endl; return 1; } else { cout << "accept success" <<
endl; cout << inet_ntoa(remote_addr.sin_addr) << ":" << ntohs(remote_addr.
sin_port) << endl; show_connect(connfd); //fds.push_back(connfd); evt.data.fd =
connfd; evt.events = EPOLLIN; epoll_ctl(epollfd,EPOLL_CTL_ADD,connfd,&evt); fds.
push_back(connfd); ++count; } } else { int connfd = revt[i].data.fd; char buffer
[1024] = {0}; int n = read(connfd,buffer,1024); // 读取客户端发过来的信息 if(n == 0) { cout
<< "client exit" << endl; close(connfd); // 关掉推出的连接 epoll_ctl(epollfd,
EPOLL_CTL_DEL,connfd,revt+i); fds.remove(connfd); --count; break; } else { for(
auto fd:fds) { // 发送信息给所有的客户端 if(fd == connfd) continue; write(fd,buffer,1024);
} } } } } close(epollfd); // 7. 关闭套接字 close(listenfd); }