libevent 库实在是轻量级,下面用不到百行代码,实现一个简单的服务器,其功能是在9995端口监听连接,有连接上来就给回复:“Hello, World!”。另外还添加了一个信号处理回调,当你按 Ctrl+C 时,服务器会清理资源,干干净净地退出,这是一个服务器开发者必备素质:)
客户端就马马虎虎地写一个了,只用到C标准库就行。
最后,还是提醒一下,都是linux编程,libevent对windows支持并不好,windows也不太需要开源网络库,.Net中有丰富而强大的网络支持。
服务端代码 helloworld.c
0001#include <string.h>
0002#include <errno.h>
0003#include <stdio.h>
0004#include <signal.h>
0005#include <unistd.h>
0006
0007#include <event2/bufferevent.h>
0008#include <event2/buffer.h>
0009#include <event2/listener.h>
0010
0011staticconstchar MESSAGE[] ="Hello, World!\n";
0012staticconstint PORT = 9995;
0013
0014staticvoid listener_cb(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void*);
0015staticvoid signal_cb(evutil_socket_t, short, void*);
0016
0017int main(int argc, char**argv)
0018{
0019 struct event_base *base;
0020 struct evconnlistener *listener;
0021 struct event *signal_event;
0022
0023 struct sockaddr_in sin;
0024
0025 // 初始化 libevent,libevent2推荐使用 event_base_new(),因为fork后更好用
0026 base = event_base_new();
0027 if (!base) {
0028 fprintf(stderr, "Could not initialize libevent!\n");
0029 return 1;
0030 }
0031
0032 memset(&sin, 0, sizeof(sin));
0033 sin.sin_family = AF_INET;
0034 sin.sin_port = htons(PORT);
0035
0036 // 绑定到 ip:port 监听
0037 listener = evconnlistener_new_bind(base, listener_cb, (void*)base,
0038 LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1,
0039 (struct sockaddr*)&sin,
0040 sizeof(sin));
0041
0042 if (!listener) {
0043 fprintf(stderr, "Could not create a listener!\n");
0044 return 1;
0045 }
0046
0047 // 添加一个处理信号的事件
0048 signal_event = evsignal_new(base, SIGINT, signal_cb, (void*)base);
0049
0050 if (!signal_event || event_add(signal_event, NULL)<0) {
0051 fprintf(stderr, "Could not create/add a signal event!\n");
0052 return 1;
0053 }
0054
0055 // 开工
0056 event_base_dispatch(base);
0057
0058 // 释放已分配的资源(上面函数中用过 new 的)
0059 evconnlistener_free(listener);
0060 event_free(signal_event);
0061 event_base_free(base);
0062
0063 printf("done\n");
0064 return 0;
0065}
0066
0067// 监听到有人连接,处理
0068staticvoid listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
0069 struct sockaddr *sa, int socklen, void*user_data)
0070{
0071 struct event_base *base = user_data;
0072 struct bufferevent *bev;
0073
0074 bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
0075 if (!bev) {
0076 fprintf(stderr, "Error constructing bufferevent!");
0077 event_base_loopbreak(base);
0078 return;
0079 }
0080
0081 // 向客户端发送消息 MESSAGE
0082 bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
0083}
0084
0085staticvoid signal_cb(evutil_socket_t sig, short events, void*user_data)
0086{
0087 struct event_base *base = user_data;
0088 struct timeval delay = { 2, 0 };
0089
0090 printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");
0091
0092 // 收工
0093 event_base_loopexit(base, &delay);
0094}
客户端代码 client.c
0001#include <stdio.h>0002#include <stdlib.h>
0003#include <errno.h>
0004#include <unistd.h>
0005#include <string.h>
0006#include <sys/socket.h>
0007#include <netinet/in.h>
0008#include <netdb.h>
0009
0010int main(int argc, char**argv)
0011{
0012 int sockfd = socket(AF_INET, SOCK_STREAM, 0);
0013 struct hostent *server = gethostbyname("127.0.0.1");
0014 if (server == NULL) {
0015 printf("ERROR, no such host\n");
0016 exit(0);
0017 }
0018
0019 struct sockaddr_in serv_addr;
0020 memset((char*) &serv_addr, 0, sizeof(serv_addr));
0021
0022 serv_addr.sin_family = AF_INET;
0023 memcpy((char*)server->h_addr,
0024 (char*)&serv_addr.sin_addr.s_addr,
0025 server->h_length);
0026 serv_addr.sin_port = htons(9995);
0027 if (connect( sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0){
0028 printf("error connect:%d\n", errno);
0029 exit(0);
0030 }
0031
0032 char buf[1024]= {0};
0033 int n = read( sockfd, buf,sizeof(buf));
0034 buf[n]='\0';
0035 printf("%s\n", buf);
0036
0037 close(sockfd);
0038 return 0;
0039}