目录

示例1

server.c

client.c

makefile

示例2:使用BufferEvent

server.c

client.c

makefile


关于libevent的介绍,请参见《libevent:信号、超时、回调》

示例1

代码实现了一个简单的echo server,server启动后,client端启动并连接,在cmd中输入文字,server端收到后,将文字再返回给client。

server.c

/**
You need libevent2 to compile this piece of code
Please see: http://libevent.org/
Cmd to compile this piece of code: You need libevent2 to compile this piece of code
Please see: http://libevent.org/
Cmd to compile this piece of code: gcc client.c -levent -o client.out
gcc server.c -levent -o server.out
**/
#include<stdio.h>
#include<string.h>
#include<errno.h>  #include<unistd.h>
#include<event.h>void accept_cb(int fd, short events, void* arg);
void socket_read_cb(int fd, short events, void* arg);int tcp_server_init(int port, int listen_num);int main(int argc, char const *argv[])
{/* code */int listener = tcp_server_init(9999, 10);if (listener == -1){perror("tcp_server_init error");return -1;}struct event_base* base = event_base_new();// 监听客户端请求链接事件struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST, accept_cb, base);event_add(ev_listen, NULL);event_base_dispatch(base); //调度return 0;
}void accept_cb(int fd, short events, void* arg)
{evutil_socket_t sockfd;struct sockaddr_in client;socklen_t len = sizeof(client);sockfd = accept(fd, (struct sockaddr*)&client, &len);evutil_make_socket_nonblocking(sockfd);printf("accept a client %d\n", sockfd);struct event_base* base = (struct event_base*)arg;//动态创建一个event结构体,并将其作为回调参数传递给struct event* ev = event_new(NULL, -1, 0, NULL, NULL);event_assign(ev, base, sockfd, EV_READ | EV_PERSIST, socket_read_cb, (void*)ev);event_add(ev, NULL);
}void socket_read_cb(int fd, short events, void* arg)
{char msg[4096];struct event* ev = (struct event*)arg;int len = read(fd, msg, sizeof(msg) - 1);if(len <= 0){printf("some error happen when read\n");event_free(ev);close(fd);return;}msg[len] = '\0';printf("recv the client msg : %s\n", msg);char reply_msg[4096] = "I have received the msg: ";strcat(reply_msg + strlen(reply_msg), msg);write(fd, reply_msg, strlen(reply_msg));
}typedef struct sockaddr SA;
int tcp_server_init(int port, int listen_num)
{  int errno_save;  evutil_socket_t listener;  listener = socket(AF_INET, SOCK_STREAM, 0);  if( listener == -1 )  return -1;  //允许多次绑定同一个地址。要用在socket和bind之间  evutil_make_listen_socket_reuseable(listener);  struct sockaddr_in sin;  sin.sin_family = AF_INET;  sin.sin_addr.s_addr = 0;  sin.sin_port = htons(port);  if( bind(listener, (SA*)&sin, sizeof(sin)) < 0 )  goto error;  if( listen(listener, listen_num) < 0)  goto error;  //跨平台统一接口,将套接字设置为非阻塞状态  evutil_make_socket_nonblocking(listener);  return listener;  error:  errno_save = errno;  evutil_closesocket(listener);  errno = errno_save;  return -1;
}

client.c

/**
You need libevent2 to compile this piece of code
Please see: http://libevent.org/
Cmd to compile this piece of code: gcc client.c -levent -o client.out
gcc server.c -levent -o server.out**/
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<errno.h>
#include<unistd.h>  #include<stdio.h>
#include<string.h>
#include<stdlib.h>  #include<event.h>
#include<event2/util.h>  int tcp_connect_server(const char* server_ip, int port);
void cmd_msg_cb(int fd, short events, void* arg);
void socket_read_cb(int fd, short events, void *arg);  int main(int argc, char** argv)
{  if( argc < 3 )  {  printf("please input 2 parameter\n");  return -1;  }  //两个参数依次是服务器端的IP地址、端口号  int sockfd = tcp_connect_server(argv[1], atoi(argv[2]));  if( sockfd == -1)  {  perror("tcp_connect error ");  return -1;  }  printf("connect to server successful\n");  struct event_base* base = event_base_new();  struct event *ev_sockfd = event_new(base, sockfd,  EV_READ | EV_PERSIST,  socket_read_cb, NULL);  event_add(ev_sockfd, NULL);  //监听终端输入事件  struct event* ev_cmd = event_new(base, STDIN_FILENO,  EV_READ | EV_PERSIST, cmd_msg_cb,  (void*)&sockfd);  event_add(ev_cmd, NULL);  event_base_dispatch(base);   //调度printf("finished \n");  return 0;
}  void cmd_msg_cb(int fd, short events, void* arg)
{  char msg[1024];  int ret = read(fd, msg, sizeof(msg));  if( ret <= 0 )  {  perror("read fail ");  exit(1);  }  int sockfd = *((int*)arg);  //把终端的消息发送给服务器端  //为了简单起见,不考虑写一半数据的情况  write(sockfd, msg, ret);
}  void socket_read_cb(int fd, short events, void *arg)
{  char msg[1024];  //为了简单起见,不考虑读一半数据的情况  int len = read(fd, msg, sizeof(msg)-1);  if( len <= 0 )  {  perror("read fail ");  exit(1);  }  msg[len] = '\0';  printf("recv %s from server\n", msg);
}  typedef struct sockaddr SA;
int tcp_connect_server(const char* server_ip, int port)
{  int sockfd, status, save_errno;  struct sockaddr_in server_addr;  memset(&server_addr, 0, sizeof(server_addr) );  server_addr.sin_family = AF_INET;  server_addr.sin_port = htons(port);  status = inet_aton(server_ip, &server_addr.sin_addr);  if( status == 0 ) //the server_ip is not valid value  {  errno = EINVAL;  return -1;  }  sockfd = socket(PF_INET, SOCK_STREAM, 0);  if( sockfd == -1 )  return sockfd;  status = connect(sockfd, (SA*)&server_addr, sizeof(server_addr) );  if( status == -1 )  {  save_errno = errno;  close(sockfd);  errno = save_errno; //the close may be error  return -1;  }  evutil_make_socket_nonblocking(sockfd);  return sockfd;
}  

makefile

all:gcc client.c -levent -o client.outgcc server.c -levent -o server.out

示例2:使用BufferEvent


在上面的代码中,client的cmd中有信息输入时,client直接将数据写入到fd中,server中收到信息后,也是直接将信息写入到fd中,因为fd是非阻塞的,所以不能保证正确。那么需要一个自己管理的缓存来管理自己的数据。那么步骤将稍微有些变化,如下所示:

  1. 设置scokfd为nonblocking;
  2. 使用bufferevent_socket_new创建一个struct bufferevent* bev,关联上面的sockfd,并托管给event_base;
  3. 使用bufferevent_setcb(bev, read_cb, write_cb, error_cb, (void*)arg);
  4. 使用buffevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST)来启动read/write事件

server.c

/**
You need libevent2 to compile this piece of code
Please see: http://libevent.org/
Cmd to compile this piece of code: gcc client.c -levent -o client.out
gcc server.c -levent -o server.out**/#include<stdio.h>
#include<string.h>
#include<errno.h>#include<event.h>
#include<event2/bufferevent.h>void accept_cb(int fd, short events, void* arg);
void socket_read_cb(struct bufferevent* bev, void* arg);
void event_cb(struct bufferevent *bev, short event, void *arg);
int tcp_server_init(int port, int listen_num);int main(int argc, char** argv)
{int listener = tcp_server_init(9999, 10);if( listener == -1 ){perror(" tcp_server_init error ");return -1;}struct event_base* base = event_base_new();//添加监听客户端请求连接事件struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST,accept_cb, base);event_add(ev_listen, NULL);event_base_dispatch(base);event_base_free(base);return 0;
}void accept_cb(int fd, short events, void* arg)
{evutil_socket_t sockfd;struct sockaddr_in client;socklen_t len = sizeof(client);sockfd = accept(fd, (struct sockaddr*)&client, &len );evutil_make_socket_nonblocking(sockfd);printf("accept a client %d\n", sockfd);struct event_base* base = (struct event_base*)arg;struct bufferevent* bev = bufferevent_socket_new(base, sockfd, BEV_OPT_CLOSE_ON_FREE);bufferevent_setcb(bev, socket_read_cb, NULL, event_cb, arg);bufferevent_enable(bev, EV_READ | EV_PERSIST);
}void socket_read_cb(struct bufferevent* bev, void* arg)
{char msg[4096];size_t len = bufferevent_read(bev, msg, sizeof(msg));msg[len] = '\0';printf("recv the client msg: %s", msg);char reply_msg[4096] = "I have recvieced the msg: ";strcat(reply_msg + strlen(reply_msg), msg);bufferevent_write(bev, reply_msg, strlen(reply_msg));
}void event_cb(struct bufferevent *bev, short event, void *arg)
{if (event & BEV_EVENT_EOF)printf("connection closed\n");else if (event & BEV_EVENT_ERROR)printf("some other error\n");//这将自动close套接字和free读写缓冲区bufferevent_free(bev);
}typedef struct sockaddr SA;
int tcp_server_init(int port, int listen_num)
{int errno_save;evutil_socket_t listener;listener = socket(AF_INET, SOCK_STREAM, 0);if( listener == -1 )return -1;//允许多次绑定同一个地址。要用在socket和bind之间evutil_make_listen_socket_reuseable(listener);struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_addr.s_addr = 0;sin.sin_port = htons(port);if( bind(listener, (SA*)&sin, sizeof(sin)) < 0 )goto error;if( listen(listener, listen_num) < 0)goto error;//跨平台统一接口,将套接字设置为非阻塞状态evutil_make_socket_nonblocking(listener);return listener;error:errno_save = errno;evutil_closesocket(listener);errno = errno_save;return -1;
}

client.c

/**
You need libevent2 to compile this piece of code
Please see: http://libevent.org/
Cmd to compile this piece of code: gcc client.c -levent -o client.out
gcc server.c -levent -o server.out**/
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<errno.h>
#include<unistd.h>  #include<stdio.h>
#include<string.h>
#include<stdlib.h>  #include<event.h>
#include<event2/bufferevent.h>
#include<event2/buffer.h>
#include<event2/util.h>  int tcp_connect_server(const char* server_ip, int port);
void cmd_msg_cb(int fd, short events, void* arg);
void server_msg_cb(struct bufferevent* bev, void* arg);
void event_cb(struct bufferevent *bev, short event, void *arg);  int main(int argc, char** argv)
{  if( argc < 3 )  {  printf("please input 2 parameter\n");  return -1;  }  //两个参数依次是服务器端的IP地址、端口号  int sockfd = tcp_connect_server(argv[1], atoi(argv[2]));  if( sockfd == -1)  {  perror("tcp_connect error ");  return -1;  }  printf("connect to server successful\n");  struct event_base* base = event_base_new();  struct bufferevent* bev = bufferevent_socket_new(base, sockfd,  BEV_OPT_CLOSE_ON_FREE);  //监听终端输入事件  struct event* ev_cmd = event_new(base, STDIN_FILENO,  EV_READ | EV_PERSIST, cmd_msg_cb,  (void*)bev);  event_add(ev_cmd, NULL);  //当socket关闭时会用到回调参数  bufferevent_setcb(bev, server_msg_cb, NULL, event_cb, (void*)ev_cmd);  bufferevent_enable(bev, EV_READ | EV_PERSIST);  event_base_dispatch(base);  printf("finished \n");  return 0;
}  void cmd_msg_cb(int fd, short events, void* arg)
{  char msg[1024];  int ret = read(fd, msg, sizeof(msg));  if( ret < 0 )  {  perror("read fail ");  exit(1);  }  struct bufferevent* bev = (struct bufferevent*)arg;  //把终端的消息发送给服务器端  bufferevent_write(bev, msg, ret);
}  void server_msg_cb(struct bufferevent* bev, void* arg)
{  char msg[1024];  size_t len = bufferevent_read(bev, msg, sizeof(msg));  msg[len] = '\0';  printf("recv %s from server\n", msg);
}  void event_cb(struct bufferevent *bev, short event, void *arg)
{  if (event & BEV_EVENT_EOF)  printf("connection closed\n");  else if (event & BEV_EVENT_ERROR)  printf("some other error\n");  //这将自动close套接字和free读写缓冲区  bufferevent_free(bev);  struct event *ev = (struct event*)arg;  //因为socket已经没有,所以这个event也没有存在的必要了  event_free(ev);
}  typedef struct sockaddr SA;
int tcp_connect_server(const char* server_ip, int port)
{  int sockfd, status, save_errno;  struct sockaddr_in server_addr;  memset(&server_addr, 0, sizeof(server_addr) );  server_addr.sin_family = AF_INET;  server_addr.sin_port = htons(port);  status = inet_aton(server_ip, &server_addr.sin_addr);  if( status == 0 ) //the server_ip is not valid value  {  errno = EINVAL;  return -1;  }  sockfd = socket(PF_INET, SOCK_STREAM, 0);  if( sockfd == -1 )  return sockfd;  status = connect(sockfd, (SA*)&server_addr, sizeof(server_addr) );  if( status == -1 )  {  save_errno = errno;  close(sockfd);  errno = save_errno; //the close may be error  return -1;  }  evutil_make_socket_nonblocking(sockfd);  return sockfd;
}  

makefile

all:gcc client.c -levent -o client.outgcc server.c -levent -o server.out

libevent的两个服务端、客户端示例(C语言)相关推荐

  1. java mina tcp_Mina TCP服务端客户端 示例

    服务端代码:package com.xd.nms.example; import java.io.IOException; import java.net.InetSocketAddress; imp ...

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

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

  3. 一个简单的完成端口(服务端/客户端)类

    一个简单的完成端口(服务端/客户端)类 作者:spinoza 翻译:麦子芽儿, POWERCPP(后面部分内容) 下载源代码 原文网址:http://www.codeproject.com/KB/IP ...

  4. react服务端/客户端,同构代码心得

    FKP-REST是一套全栈javascript框架 react服务端/客户端,同构代码心得 作者:webkixi react服务端/客户端,同构代码心得 服务端,客户端同构一套代码,大前端的梦想,为了 ...

  5. restful服务端客户端_测试RESTful服务的客户端

    restful服务端客户端 开发使用RESTful Web API的应用程序可能意味着开发服务器和客户端. 为服务器端编写集成测试可以像使用Arquillian启动服务器一样容易,并且可以通过REST ...

  6. netty java_GitHub - leihuazhe/Java11-Netty-Demo: 基于Java11 构建的 netty 服务端客户端 模块化例子...

    Java11-Netty-Demo Java11 基于maven构建的简单的服务端客户端分离模块调用的例子 Java 11 从 Java9 开始引入了模块化的概念.使用Java11 也需要以模块化的方 ...

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

    TCP/IP网络编程之基于TCP的服务端/客户端(一) 理解TCP和UDP 根据数据传输方式的不同,基于网络协议的套接字一般分为TCP套接字和UDP套接字.因为TCP套接字是面向连接的,因此又称为基于 ...

  8. 网络云盘项目——HTTP接口介绍、功能介绍、服务端/客户端代码解析

    一.本文目的 本项目分为6篇博客文章完成: 1.项目总体介绍:https://blog.csdn.net/qq_41453285/article/details/107871393. 2.Redis部 ...

  9. Python Django断点下载(服务端/客户端)

    断点下载 背景     断点续传/断点下载一直是每个系统最实用的功能,最近公司在复杂的网络环境(国外vps)下载东西遇到问题,有些文件下载的时候很慢,并且可能会下不下来,这种情况对一个系统的稳定性构成 ...

最新文章

  1. 2007年你必须学习的10项.NET技术
  2. 终极解决方式——找到占用U盘的程序
  3. Windows下的ping
  4. datastage 函数_DataStage_Transformer常用函数
  5. CVPR 2020|打脸SOTA!不能忍,谷歌发起图像匹配挑战赛
  6. php71+yum源+epel,搭建CentOS在线yum源镜像服务器
  7. Python变量的作用范围
  8. 蓝桥杯 ADV-65 算法提高 格子位置
  9. ul阻燃标准有几个等级_UL阻燃等级介绍说明
  10. PHP语言基本数据类型
  11. 1436 旅行终点站
  12. 七、手把手教你搭建SpringCloudAlibaba之Sentinel实现流量控制
  13. centos虚拟机上网慢的问题
  14. 《搞不定人,你如何带团队?》读书记录
  15. rtb中的win_广告:RTB
  16. Openvino 模型文件部署推理
  17. c语言摄氏度字符,c语言摄氏度与华氏温度如何转换
  18. 输入年月日,获得下个月的同一天,如果该天不存在,则顺延一天
  19. 小议并实战go包------顺便说说go中的GOROOT,GOPATH和src,pkg,bin
  20. spring tool suit设置屏幕护眼保护色

热门文章

  1. bzoj 2761: [JLOI2011]不重复数字【hash】
  2. Spring第七弹—依赖注入之注解方式注入及编码解析@Resource原理
  3. python操作各种excel库
  4. 桶排序Bucket sort(转)
  5. LoadRunner 使用虚拟IP测试流程
  6. Struts2的输入验证(三)-短路验证与非字段验证
  7. jquery.ui.sortable 笔记
  8. java c static,java-是否可以禁用静态最终变量的javac内联?
  9. 举例说明操作系统在计算机系统中的重要地位,第一二三章作业参考答案
  10. 斜视术后融合训练方法_做斜视手术两年后又复发了怎么办?