一、实现思路
1、服务器
1)socket()
2)set_sockopt() 端口复用。
3)bind() 绑定服务器。
4)listen() 设置监听上限。
5)epoll_create() 创建epoll模型,efd指向红黑树跟结点。
7)epoll_ctl() //将lfd及对应的结构体挂到树上,efd可以找到该树。
8)循环监听:epoll_wait() //epoll为server阻塞监听事件,ep为struct epoll_event数组输出,OPEN_MAX为数组容量,-1 表示阻塞。
9)进入第二层循环,循环次数为epoll_wait的返回值。
10)入股哦不是“读”事件,继续循环。
11)判断满足事件的fd时不时lfd。
12)是。接收连接请求——》挂到树上。
13)不是。读出sockfd——》read:为0,从树上删除结点;为负,出错处理;其它,执行功能。
14)末尾。关闭lfd。关闭efd树。
2、客户端
1)socket() 创建socket。
2)connect() 与服务器建立连接。
3)write() 写数据到socket的写缓冲,将数据发送到服务器。
6)close() 关闭fd。
二、详细代码
1、服务器
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <errno.h>
#include <ctype.h>
#include "warp.h"
#define OPEN_MAX 5000
#define SERV_PORT 666
#define MAXLINE 8192
int main (int argc, char *argv[])
{
int i, listenfd, connfd, sockfd;
int n, num = 0;
ssize_t nready, efd, res;
char buf[MAXLINE], str[INET_ADDRSTRLEN]; //INET_ADDRSTRLEN这个宏定义的数字是IP地址字符串的大小
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
struct epoll_event tep, ep[OPEN_MAX]; //tep是临时变量;ep为epoll_wait的输出数组,保存了被触发事件的结点。
listenfd = Socket (AF_INET, SOCK_STREAM, 0); //创建一个用于监听客户端的套接字
int opt = 1;
setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); //端口复用
bzero (&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons (SERV_PORT);
servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
Bind (listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); //绑定服务器
Listen (listenfd, 20); //设置监听上限
efd = epoll_create (OPEN_MAX); //创建epoll的红黑树
if (efd == -1)
PERROR("epoll_create errno");
tep.events = EPOLLIN; tep.data.fd = listenfd; //监听listenfd的读事件,即客户端的请求
res = epoll_ctl (efd, EPOLL_CTL_ADD, listenfd, &tep); //挂上树
if (res == -1)
PERROR ("epoll_ctl error");
for (; ;)
{
nready = epoll_wait (efd, ep, OPEN_MAX, -1); 循环监听
if (nready == -1)
PERROR ("epoll_wait error");
for (i = 0; i < nready; i++)
{
if (!ep[i].events & EPOLLIN) //只监听读事件
continue;
if (ep[i].data.fd == listenfd) //有客户端发出连接请求
{
clilen = sizeof (cliaddr);
connfd = Accept (listenfd, (struct sockaddr*)&cliaddr,&clilen);
printf ("receive from %s at PORT %d\n",
inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port));
printf ("cfd %d---client %d\n", connfd, ++num);
tep.events = EPOLLIN; tep.data.fd =connfd;
res = epoll_ctl (efd, EPOLL_CTL_ADD, connfd, &tep);
if (res == -1)
PERROR ("epoll_ctl error");
}
else //已连接的结点发出的事件
{
sockfd = ep[i].data.fd;
n = Read (sockfd, buf, MAXLINE);
if (n == 0)
{
res = epoll_ctl (efd, EPOLL_CTL_DEL, sockfd, NULL);
if (res == -1)
PERROR ("epoll_ctl error");
Close (sockfd);
printf ("client[%d] closed connect\n", sockfd);
}
else if (n < 0)
{
perror ("read n < 0 error: ");
res = epoll_ctl (efd, EPOLL_CTL_DEL, sockfd, NULL);
Close (sockfd);
}
else
{
for (i=0; i<n ;i++)
buf[i] = toupper (buf[i]);
Write (STDOUT_FILENO, buf, n);
Writen (sockfd, buf, n);
}
}
}
}
Close (listenfd);
Close (efd);
return 0;
}
2、客户端
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <errno.h>
#include "warp.h"
#define SEVR_PORT 666
int main (void)
{
int cfd;
struct sockaddr_in serv_addr;
int count = 10;
char buf[1024] = {0};
cfd = Socket (AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons (SEVR_PORT);
inet_pton (AF_INET, "127.0.0.1", &serv_addr.sin_addr.s_addr);
Connect (cfd, (struct sockaddr *)&serv_addr, sizeof (serv_addr));
while (count--)
{
int ret = 0 ;
write (cfd, "I LOVE U\n", 9);
ret = read (cfd, buf, strlen (buf));
//write (STDOUT_FILENO, buf, ret);
printf ("%s", buf);
sleep (1);
}
close (cfd);
return 0;
}