服务端具有群发、回射功能
采用epoll方式、多客户端进行操作
可以参考一下:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <poll.h>
#include <sys/epoll.h>
#define PORT 8000
#define FWQIP 0 //可改为自己IP
int main(int argc, char* argv[])
{
int lfd=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in seraddr,cliaddr;
seraddr.sin_family=AF_INET;
seraddr.sin_port=htons(PORT);
seraddr.sin_addr.s_addr=FWQIP;
int a=bind(lfd,(struct sockaddr*)&seraddr,sizeof(seraddr));
if(a<0)
{
perror("bind error:");
return 0;
}
listen(lfd,64);
socklen_t len=sizeof(cliaddr);
//创建一个epoll对象
int epfd = epoll_create(64);
//结构体表示这个文件描述的监听事件,和如何识别他(data域)
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = lfd;
//把lfd放到红黑树里面
epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &event);
//epoll_wait需要一个结构体来保存返回的触发事件,创建结构体。
struct epoll_event events[1024];
int i;//循环因子
while(1)
{
int epollret = epoll_wait(epfd, events, 1024, -1);//返回触发的事件,-1表示非阻塞
if(epollret < 0)
{
perror("epoll_wait error:");
exit(1);
}
else//epoll_wait没有出错,则需要对返回来的events数组进行处理
{
for(i=0; i < epollret; i++)
{
if(events[i].events & EPOLLIN)//事件触发
{
int pfd = events[i].data.fd;
if(pfd == lfd)//表示lfd事件触发,有新的客户端请求连接
{
int cfd=accept(lfd,(struct sockaddr*)&cliaddr,&len);
if(cfd < 0)
{
perror("accept error:");
exit(1);
}
int cliport=ntohs(cliaddr.sin_port);//网络端口号转本地端口号
char det[1025];
inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, det,sizeof(det));//网络IP转本地IP
printf("客户端已连接 IP = %s 端口号 = %d\n", det, cliport);
//把cfd加入到红黑树中
event.events = EPOLLIN;//还是监听读事件
event.data.fd = cfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &event);//添加到红黑树
}
else//不是lfd则做回射
{
char buf[1024];
int rr = read(pfd, buf, sizeof(buf));
if(rr < 0)
{
perror("read error:");
exit(1);
}
else if(rr == 0)
{
printf("客户端已断开\n");
epoll_ctl(epfd, EPOLL_CTL_DEL, pfd, NULL);//删除文件描述符。
}
else
{
write(1, buf, rr);
write(pfd, buf, rr);
}
}
}
}
}
}
return 0;
}