libevent2入門例-簡單的伺服器(也有簡短客戶端)
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}