https://blog.csdn.net/y396397735/article/details/50680359

本例实现如下功能:

支持多客户端与一个服务端进行通信,客户端给服务端发送字符串数据,服务端将字符串中小写转为大写后发送回客户端,客户端打印输出经转换后的字符串。 
例如:发送 abcde,打印输出 ABCDE 
服务端源码如下:

/*server.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <errno.h>#define BUFSIZE 666
#define SERV_PORT 8000
#define OPEN_MAX 1024int main()
{int i, j, maxi, listenfd, connfd, sockfd;int nready, efd, res;ssize_t n;char buf[BUFSIZE], str[INET_ADDRSTRLEN];socklen_t clilen;int client[OPEN_MAX];struct sockaddr_in cliaddr, servaddr;struct epoll_event tep, ep[OPEN_MAX];//监听事件/*分配一个网络通信套接字,监听文件描述符listenfd*/listenfd = socket(AF_INET, SOCK_STREAM, 0);/*初始化 IP类型 端口*/bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);/*将listenfd绑定服务端地址*/bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));/*监听请求*/listen(listenfd, 20);/*将客户端标识初始化为-1*/for(i = 0; i < OPEN_MAX; i++){client[i] = -1;}maxi = -1;/*告诉内核要监听的文件描述符个数 OPEN_MAX = 1024*/efd = epoll_create(OPEN_MAX);if(efd == -1){perror("epoll_create");}tep.events = EPOLLIN;/*监听文件描述符的可读事件*/tep.data.fd = listenfd;/*设置为监听的文件描述符*//*控制epoll监控的文件描述符上的事件*/res = epoll_ctl(efd, EPOLL_CTL_ADD/*注册新的fd到efd*/, listenfd, &tep);if(res == -1)perror("epoll_ctl");for(;;){/*等待所监控文件描述符上有事件的产生,阻塞监听*/nready = epoll_wait(efd, ep, OPEN_MAX, -1);if(nready == -1)perror("epoll_wait");for(i = 0; i < nready; i++){if(!(ep[i].events & EPOLLIN))/*若不是EPOLLIN事件,不做往下的处理*/continue;if(ep[i].data.fd == listenfd){ /*若是EPOLLIN,执行连接,接受请求*/clilen = sizeof(cliaddr);/*接受请求,分配新文件描述符connfd进行通信*/connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);printf("received from %s at PORT %d\n", (char*)inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port));/*若将此新客户端添加至客户端集中*/for(j = 0; j < OPEN_MAX; j++)if(client[j] < 0){client[j] = connfd;break;}if(j == OPEN_MAX)perror("客户端超过限制");if(j > maxi)maxi = j;//保证maxi为最大文件描述符tep.events = EPOLLIN;tep.data.fd = connfd;res = epoll_ctl(efd, EPOLL_CTL_ADD/*注册新的connfd到efd*/, connfd, &tep);if(res == -1)perror("epoll_ctl");}else{/*处理efd中监听的客户端请求*/sockfd = ep[i].data.fd;n = read(sockfd, buf, BUFSIZE);if(n == 0){ /*读取若为空*/for(j = 0; j <= maxi; j++){if(client[j] == sockfd){client[j] = -1;break;}}/*清除对sockfd文件描述符事件的监听*/res = epoll_ctl(efd, EPOLL_CTL_DEL, sockfd, NULL);if(res == -1)perror("epoll_ctl");close(sockfd);printf("client[%d] closed connection\n", j);}else{/*非空则处理客户端信息*/for(j = 0; j<n; j++)buf[j] = toupper(buf[j]);/*写入与客户端通信的文件描述符sockfd*/write(sockfd, buf, n);}}}}/*关闭监听*/close(listenfd);close(efd);return 0;
}

客户端源码如下:

/*client.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <errno.h>#define BUFSIZE 666
#define SERV_PORT 8000
#define OPEN_MAX 1024int main(int argc, char *argv[])
{struct sockaddr_in servaddr;char buf[BUFSIZE];int sockfd, n;sockfd = socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);servaddr.sin_port = htons(SERV_PORT);/*连接服务端*/connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));while(fgets(buf, BUFSIZE, stdin) != NULL){/*通过sockfd给服务端发送数据*/write(sockfd, buf, strlen(buf));n = read(sockfd, buf, BUFSIZE);if(n == 0)printf("the other side has been closed.\n");else/*打印输出服务端传过来的数据*/write(STDOUT_FILENO, buf, n);}close(sockfd);return 0;
}

编译及执行

在终端1先执行:

yu@ubuntu:~/Linux/217/epoll$ ls
client.c  server.c
yu@ubuntu:~/Linux/217/epoll$ gcc -o client client.c
yu@ubuntu:~/Linux/217/epoll$ gcc -o server server.c
yu@ubuntu:~/Linux/217/epoll$ ./server
  • 1
  • 2
  • 3
  • 4
  • 5

另开一终端2:

yu@ubuntu:~/Linux/217/epoll$ ./client
hey how are you
HEY HOW ARE YOU
bye
BYE

再另开一终端3:

yu@ubuntu:~/Linux/217/epoll$ ./client
i am here 007
I AM HERE 007
hehe
HEHE

最后开一终端4:

yu@ubuntu:~/Linux/217/epoll$ ./client
i am 008
I AM 008
zai jian
ZAI JIAN

关闭3个客户端(CTR+C)后服务端窗口:

yu@ubuntu:~/Linux/217/epoll$ ./server
received from 127.0.0.1 at PORT 58385
received from 127.0.0.1 at PORT 58386
received from 127.0.0.1 at PORT 58387
client[2] closed connection
client[1] closed connection
client[0] closed connection

socket编程 -- epoll模型服务端/客户端通信的实现相关推荐

  1. linux socket编程epoll模型实现群发消息

    1.实现功能 本代码主要实现了socket编程epoll模型实现多个客户端连接服务器,客户端可以进行群发消息和接收用户输入文本信息,然后发送该信息给服务器,服务器收到后发送应答信息.客户端接收并显示该 ...

  2. Netty 的基本简单实例【服务端-客户端通信】

    Netty是建立在NIO基础之上,Netty在NIO之上又提供了更高层次的抽象. 在Netty里面,Accept连接可以使用单独的线程池去处理,读写操作又是另外的线程池来处理. Accept连接和读写 ...

  3. Go实现简单的TCP服务端客户端通信(有黏包)

    目录 客户端代码 服务端代码 封包协议 客户端代码 // socket_stick/client2/main.gofunc main() {conn, err := net.Dial("tc ...

  4. php winform通信,C# Winform 通过Socket实现客户端和服务端TCP通信

    操作界面如下: 1.声明Socket 第一个参数:寻址方式,第二个参数:传输数据的方式,第三个参数:通信协议 Socket socket = new Socket(AddressFamily.Inte ...

  5. Java中利用socket实现简单的服务端与客户端的通信(基础级)

    在上一篇文章中,简单的介绍了java中入门级的socket编程,简单的实现了客户端像服务器端发送数据,服务器端将数据接收并显示在控制台,没有涉及多线程.上一篇文章的链接:Java中利用socket实现 ...

  6. Java中利用socket实现简单的服务端与客户端的通信(中级)——实现任意双向通信

    本文计划采用socket实现客户端和服务端的任意双向通信,即客户端可以随时给服务端发消息,服务端也可以随时给客户端发消息,最终结果就是一个类似与QQ的聊天软件的功能. 以下代码可以直接拷贝到Eclip ...

  7. php 连接socket服务器_PHP-Socket服务端客户端发送接收通信实例详解

    Socket介绍 什么是socket 所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过"套接字"向网络发出请求 ...

  8. linux 进程sockfd fork,Linux下多进程服务端客户端模型一(单进程与多进程模型)...

    本文将会简单介绍Linux下如何利用C库函数与系统调用编写一个完整的.初级可用的C-S模型. 一.基本模型: 1.1   首先服务器调用socket()函数建立一个套接字,然后bind()端口,开始l ...

  9. TCP/IP网络编程之基于TCP的服务端/客户端(二)

    回声客户端问题 上一章TCP/IP网络编程之基于TCP的服务端/客户端(一)中,我们解释了回声客户端所存在的问题,那么单单是客户端的问题,服务端没有任何问题?是的,服务端没有问题,现在先让我们回顾下服 ...

最新文章

  1. IntelliJ IDEA使用记录
  2. 我为什么选择在北上广深打拼?
  3. yaml格式,给Java类绑定数据
  4. Esfog_UnityShader教程_UnityShader语法实例浅析
  5. iphone储存空间系统怎么清理_系统项占用了 iPhone 过多的储存空间怎么办?
  6. centos下打包electron_从零搭建Electron应用 的一系列简单的 Demo
  7. 化工企业数据分析平台项目之应收款分析
  8. 如何用开源经历为你的简历增加光彩
  9. 为什么我电脑的所有浏览器都开不了网页
  10. 某天是星期几 + 三目运算符的一些错误操作解释
  11. 工业物联网实践指南----专注生产制造活动
  12. elasticsearch APM功能全解 一
  13. 电子元器件B2B电商平台建设方案:优化企业商流,拓宽B2B交易渠道
  14. Android 人脸识别签到(二)
  15. Java调用aliyun OCR图文识别
  16. CSUST选拔赛题解之-Problem H: 逃出监狱
  17. 《绝版游戏之地心护核者》
  18. .net 后台数据校验,电话号码,邮箱地址,IP有效性
  19. python-查找字符串位置
  20. 如何让读者看完公众号文章后关注你?做好这几点

热门文章

  1. AtCoder Beginner Contest 084(AB)
  2. 五、创建Bean的三种方式
  3. autoLayout自动布局
  4. awk 多文件操作2种实现方法
  5. WCF学习(五)数据契约之已知类型
  6. tomcat启动java项目_Java web项目启动Tomcat报错解决方案
  7. es springboot 不设置id_springboot整合ES_文档ID删除
  8. 百米路由器2登陆地址_腾达无线路由器怎么安装,真的不错
  9. server2016做文件服务器,『配置』服务器搭建 Office Online Server2016 实现文档预览 番外 错误篇...
  10. Linux入门笔记——cal、date、free、clear、history、man、whatis、uname