1、直接上TCP Server源码,这种方法没有使用向muduo那样的活塞式buffer,可谓简单粗暴:

#include

#include

#include

#include

#include

#include

#include

#include /*setrlimit */

#include

#include

#include

#include

#include

#include

#include

#include

#define IPADDRESS "127.0.0.1"

#define PORT 8011

#define MAXSIZE 1024

#define LISTENQ 5

#define FDSIZE 50000

#define EPOLLEVENTS 100

int stop_server = 0;

//函数声明

//创建套接字并进行绑定

static int socket_bind(const char* ip,int port);

//IO多路复用epoll

static void do_epoll(int listenfd);

//事件处理函数

static void handle_events(int epollfd,struct epoll_event *events,int num,int listenfd,char *buf);

//处理接收到的连接

static void handle_accpet(int epollfd,int listenfd);

//读处理

static void do_read(int epollfd,int fd,char *buf);

//写处理

static void do_write(int epollfd,int fd,char *buf);

//添加事件

static void add_event(int epollfd,int fd,int state);

//修改事件

static void modify_event(int epollfd,int fd,int state);

//删除事件

static void delete_event(int epollfd,int fd,int state);

//other

static int do_error(int fd, int *error);

static int setnonblocking(int fd);

static void daemonize(void);

static int set_fdlimit();

static void signal_exit_handler();

static void signal_exit_func(int signo);

int main(int argc,char *argv[])

{

//设置每个进程允许打开的最大文件数,socket

if (set_fdlimit() < 0)

{

return -1;

}

int background = 0;

if (background)

{

daemonize();

}

//设置信号处理,SIG_IGN表示忽略信号,SIG_DFL表示使用信号的默认处理方式

//signal(SIGHUP, SIG_IGN); //开启的话,就捕获不到终端窗口关闭的信号了。即窗口关闭,进程仍然进行。

signal(SIGPIPE, SIG_IGN);

/*

if (argc != 2) {

fprintf(stderr, "Usage: %s port\n", argv[0]);

return 1;

}

int port = atoi(argv[1]);*/

int listenfd;

listenfd = socket_bind(IPADDRESS,PORT);

listen(listenfd,LISTENQ);

printf("start listening...\n");

signal_exit_handler();

do_epoll(listenfd);

return 0;

}

static int socket_bind(const char* ip,int port)

{

int listenfd;

struct sockaddr_in servaddr;

listenfd = socket(AF_INET,SOCK_STREAM,0);

if (listenfd == -1)

{

perror("socket error:");

exit(1);

}

bzero(&servaddr,sizeof(servaddr));

servaddr.sin_family = AF_INET;

//inet_pton(AF_INET,ip,&servaddr.sin_addr);

servaddr.sin_port = htons(port);

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

int error;

int reuse = 1;

int ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

if (ret == -1)

{

return do_error(listenfd, &error);

}

if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == -1)

{

perror("bind error: ");

exit(1);

}

return listenfd;

}

static void do_epoll(int listenfd)

{

int epollfd;

struct epoll_event events[EPOLLEVENTS];

int ret;

char buf[MAXSIZE];

memset(buf,0,MAXSIZE);

//创建一个描述符

int error;

epollfd = epoll_create(1024);//1024 is just a hint for the kernel

if (epollfd == -1)

{

return do_error(epollfd, &error);

}

//添加监听描述符事件

add_event(epollfd,listenfd,EPOLLIN);

while ( stop_server == 0 )

{

//获取已经准备好的描述符事件

ret = epoll_wait(epollfd,events,EPOLLEVENTS,-1);

handle_events(epollfd,events,ret,listenfd,buf);

}

close(epollfd);

}

static void handle_events(int epollfd,struct epoll_event *events,int num,int listenfd,char *buf)

{

int i;

int fd;

//进行选好遍历

for (i = 0;i < num;i++)

{

fd = events[i].data.fd;

//根据描述符的类型和事件类型进行处理

if ((fd == listenfd) &&(events[i].events & EPOLLIN))

handle_accpet(epollfd,listenfd);

else if (events[i].events & EPOLLIN)

do_read(epollfd,fd,buf);

else if (events[i].events & EPOLLOUT)

do_write(epollfd,fd,buf);

}

}

static void handle_accpet(int epollfd,int listenfd)

{

int clifd;

struct sockaddr_in cliaddr;

socklen_t cliaddrlen = sizeof(cliaddr);

clifd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddrlen);

if (clifd == -1)

perror("accpet error:");

else

{

printf("accept a new client: %s:%d\n",inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port);

//添加一个客户描述符和事件

add_event(epollfd,clifd,EPOLLIN);

}

}

static void do_read(int epollfd,int fd,char *buf)

{

int nread;

nread = read(fd,buf,MAXSIZE);

if (nread == -1)

{

perror("read error:");

close(fd);

delete_event(epollfd,fd,EPOLLIN);

}

else if (nread == 0)

{

fprintf(stderr,"client close,fd=%d\n",fd);

close(fd);

delete_event(epollfd,fd,EPOLLIN);

}

else

{

printf("read message is: %s,fd=%d\n",buf,fd);

//修改描述符对应的事件,由读改为写

modify_event(epollfd,fd,EPOLLOUT);

}

}

static void do_write(int epollfd,int fd,char *buf)

{

int nwrite;

nwrite = write(fd,buf,strlen(buf));

if (nwrite == -1)

{

perror("write error:");

close(fd);

delete_event(epollfd,fd,EPOLLOUT);

}

else

modify_event(epollfd,fd,EPOLLIN);

memset(buf,0,MAXSIZE);

}

static void add_event(int epollfd,int fd,int state)

{

struct epoll_event ev;

ev.events = state;

ev.data.fd = fd;

epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev);

setnonblocking(fd);

}

static void delete_event(int epollfd,int fd,int state)

{

struct epoll_event ev;

ev.events = state;

ev.data.fd = fd;

epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,&ev);

}

static void modify_event(int epollfd,int fd,int state)

{

struct epoll_event ev;

ev.events = state;

ev.data.fd = fd;

epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&ev);

}

static int do_error(int fd, int *error)

{

fprintf(stderr, "error: %s\n", strerror(errno));

*error = errno;

while ((close(fd) == -1) && (errno == EINTR));

errno = *error;

return 1;

}

static int setnonblocking(int fd)

{

int old_option = fcntl(fd, F_GETFL);

int new_option = old_option | O_NONBLOCK;

fcntl(fd, F_SETFL, new_option);

return old_option;

}

static void daemonize(void) { //come from /redis/server.c/daemonize()

int fd;

if (fork() != 0) exit(0); /* parent exits */

setsid(); /* create a new session */

/* Every output goes to /dev/null. If Redis is daemonized but

* the 'logfile' is set to 'stdout' in the configuration file

* it will not log at all. */

if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {

dup2(fd, STDIN_FILENO);

dup2(fd, STDOUT_FILENO);

dup2(fd, STDERR_FILENO);

if (fd > STDERR_FILENO) close(fd);

}

}

static int set_fdlimit()

{

//设置每个进程允许打开的最大文件数

//这项功能等价于linux终端命令 "ulimit -n 102400"

struct rlimit rt;

rt.rlim_max = rt.rlim_cur = FDSIZE;

if (setrlimit(RLIMIT_NOFILE, &rt) == -1)

{

perror("setrlimit error");

return -1;

}

return 0;

}

static void signal_exit_handler()

{

struct sigaction sa;

memset(&sa, 0, sizeof(sa));

sa.sa_handler = signal_exit_func;

sigaction(SIGINT, &sa, NULL);//当按下ctrl+c时,它的效果就是发送SIGINT信号

sigaction(SIGTERM, &sa, NULL);//kill pid

sigaction(SIGQUIT, &sa, NULL);//ctrl+\代表退出SIGQUIT

//SIGSTOP和SIGKILL信号是不可捕获的,所以下面两句话写了等于没有写

sigaction(SIGKILL, &sa, NULL);//kill -9 pid

sigaction(SIGSTOP, &sa, NULL);//ctrl+z代表停止

//#define SIGTERM 15

//#define SIGKILL 9

//kill和kill -9,两个命令在linux中都有杀死进程的效果,然而两命令的执行过程却大有不同,在程序中如果用错了,可能会造成莫名其妙的现象。

//执行kill pid命令,系统会发送一个SIGTERM信号给对应的程序。

//执行kill -9 pid命令,系统给对应程序发送的信号是SIGKILL,即exit。exit信号不会被系统阻塞,所以kill -9能顺利杀掉进程。

}

static void signal_exit_func(int signo)

{

printf("exit signo is %d\n", signo);

stop_server = 1;

}

2、添加buffer和最小堆定时器的完整版本,请参见:

---

参考文章:

IO多路复用之epoll总结 --- 注意源码有一处错误,需要修正为:

static void handle_accpet(int epollfd,int listenfd)

{

int clifd;

struct sockaddr_in cliaddr;

socklen_t  cliaddrlen = sizeof(cliaddr);

linux c语言tcp,我个人的Linux TCP server和client测试源码,C语言(2)(★firecat推荐★)...相关推荐

  1. 易语言udp服务器广播,易语言UDP测试源码

    易语言UDP测试源码系统结构:监听子程序,输出文本,取字节集和,UDP发送,UDP发送线程,UDP连发PING,TCP连发PING,服务器1发送数据,客户1发送数据,TCP发送线程,数据到达, === ...

  2. c语言远控,远控鼠标!C语言简单编程:整舍友必备+附送实例源码!

    远控鼠标!C语言简单编程:整舍友必备+附送实例源码!-1.jpg (10.71 KB, 下载次数: 0) 2018-10-11 05:24 上传 关注<一碳科技>有更多干货等着你哦! 远控 ...

  3. C语言将不固定的表达式转换为后缀表达式(附完整源码)

    将不固定的表达式转换为后缀表达式 C语言将不固定的表达式转换为后缀表达式完整源码 C语言将不固定的表达式转换为后缀表达式完整源码 #include <stdio.h> /// for pr ...

  4. C语言十六进制数转八进制(十进制作为中介)(附完整源码)

    C语言十六进制数转八进制 C语言十六进制数转八进制完整源码 C语言十六进制数转八进制完整源码 #include <stdio.h> /// for printf() and fgets() ...

  5. [iOS] 完整源码, Swift语言 - 账号保存工具

    代码地址如下: http://www.demodashi.com/demo/15017.html 1. 需求分析 作为一个开发者,平时肯定在各个平台,网站注册了各种账号:由于太多,很多时候都是注册之后 ...

  6. 阿里api网关接口客户端demo,java实现源码,其他语言可参考

    访问阿里api网关接口客户端demo,java实现源码,其他语言可参考 上一篇文章 <阿里api网关接口创建.发布.授权.调试> 中,介绍了3个典型接口的创建并在阿里控制台调试完成,地址: ...

  7. c语言比较函数memcmp,c语言函数memcmp()如何比较内存前n个字节实例源码介绍

    c语言函数memcmp()如何比较内存前n个字节实例源码介绍.引入头文件:#include 定义memcmp()函数:int memcmp (const void *s1, const void *s ...

  8. 会员管理系统源码 php语言开发

    会员管理系统源码 php语言开发 可用于美容店,理发店,服装店,美甲店,奢侈品店等等 功能介绍: 1.常用功能 会员登记,会员充值,会员充次,商品消费(会员),商品消费(散客),快速消费(会员),快速 ...

  9. 易语言局域网 php 控制,易语言控制端源码,易语言被控制源码,易语言局域网远程控制源码...

    下面我们对易语言控制端源码,易语言被控制源码,易语言局域网远程控制源码文件阐述相关使用资料和易语言控制端源码,易语言被控制源码,易语言局域网远程控制源码文件的更新信息. 易语言控制端源码,易语言被控制 ...

最新文章

  1. Dynamics CRM中跨域调用Web API 2
  2. 配置CITRIX XML 服务与IIS 7.x共享端口
  3. 我的Java开发学习之旅------Base64的编码思想以及Java实现
  4. Qt QML实现阴影字体
  5. [转载]dbms_lob用法小结
  6. linux那些事之TLB(Translation-Lookaside Buffer)无效操作
  7. 统计一行文本的单词个数_NLP中的文本表示方法
  8. 列出spring security的所有SecurityFilterChain
  9. 良田高拍仪接口文档对接
  10. 京东手机评论文本挖掘与数据分析(Python)
  11. 上研究生学计算机去河大学校好不好,河南大学研究生,河南大学研究生值得读吗?...
  12. 程序员的密码管理之道
  13. c语言程序(十八)——迭代计算
  14. 一行命令统计出多个文件夹中的多种类型的代码行数
  15. LivePlayer.js播放器遇到悬停英文提示如何切换显示成中文
  16. 报错:Fragment not attached to an activity
  17. 世界各地的土豆代表吃法
  18. 2020全国大学生数学建模C题
  19. Android模拟器简介—更新到最新的3.0 Honeycomb
  20. [Vant] van-tabs标签页吸顶\/粘性布局在移动端适配上的一些尝试

热门文章

  1. 【Python】垃圾分类,调用阿里云API
  2. 【Verilog】模16可逆流水灯
  3. 利用FFT计算非平稳随机信号WVD分布
  4. spring cloud config将配置存储在数据库中 1
  5. [雪峰磁针石博客]计算机视觉opcencv工具深度学习快速实战1人脸识别
  6. 阿里HBase的数据管道设施实践与演进
  7. 《iOS 8案例开发大全》——实例006 实现复杂的查找和替代工作
  8. thinkphp+ajax无刷新分页并加载显示图片
  9. 李雷和韩梅梅的一次转账事务–事务系统概述
  10. JVM的垃圾回收与内存分配