简介本文向大家介绍一个C++实战项目:Libevent网络库实现简单TCP服务端及客户端,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
Libevent是一个用C语言编写的,轻量级的开源高性能事件通知库,主要有以下几个特点:事件驱动,高性能,轻量级,专注于网络,支持多平台,支持多种I/O复用技术,select,poll,epoll等,支持I/O定时器和信号事件,注册事件优先级。
#include "stdafx.h"
#include "event2/bufferevent.h"
#include "event2/buffer.h"
#include "event2/listener.h"
#include "event2/util.h"
#include "event2/event.h"
#include <event2/event-config.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <WinSock2.h>
#include <iostream>
#define IP_ADDRESS ("127.0.0.1")
#define PORT (8880)
// 连接
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** argv)
{
// 加载套接字库
WSADATA wsaData;
int iRet = 0;
iRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iRet != 0)
{
std::cout << "WSAStartup(MAKEWORD(2, 2), &wsaData) execute failed!" << std::endl;
return -1;
}
if (2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion))
{
std::cout << "WSADATA version is not correct" << std::endl;
WSACleanup();
return -1;
}
int listener = tcp_server_init(PORT, 10);
if (listener == -1)
{
perror("tcp_server_init error");
return -1;
}
printf("server inti successful\n");
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);
WSACleanup();
return 0;
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 = (event_base*)arg;
// 仅仅是为了动态创建一个event结构体
struct event* ev = event_new(NULL, -1, 0, NULL, NULL);
// 将动态创建的结构体作为event的回调参数
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 = recv(fd, msg, sizeof(msg) - 1, 0);
if (len <= 0)
{
printf("some error happen when read\n");
event_free(ev);
closesocket(fd);
return;
}
msg[len] = '\0';
printf("recv the client msg : %s\n", msg);
char reply_msg[4096] = "I have recvieced the msg: ";
strcat(reply_msg + strlen(reply_msg), msg);
int ret = send(fd, reply_msg, strlen(reply_msg), 0);
}
// 初始化
int tcp_server_init(int port, int listen_num)
{
int errno_save;
int 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, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
errno_save = errno;
evutil_closesocket(listener);
errno = errno_save;
return -1;
}
if (::listen(listener, listen_num) < 0)
{
errno_save = errno;
evutil_closesocket(listener);
errno = errno_save;
return -1;
}
// 跨平台统一接口,将套接字设置为非阻塞状态
evutil_make_socket_nonblocking(listener);
return listener;
}
#include "stdafx.h"
#include "event2/bufferevent.h"
#include "event2/buffer.h"
#include "event2/listener.h"
#include "event2/util.h"
#include "event2/event.h"
#include <event2/event-config.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <WinSock2.h>
#include <iostream>
#define IP_ADDRESS ("127.0.0.1")
#define PORT (8880)
// 连接服务器
int tcp_connect_server(const char* server_ip, int port);
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
// 发送消息
void cmd_msg_cb(int fd, char* msg);
// 接收消息
void socket_read_cb(int fd, short events, void *arg);
int main(int argc, char** argv)
{
// 加载套接字库
WSADATA wsaData;
int iRet = 0;
iRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iRet != 0)
{
return -1;
}
if (2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion))
{
WSACleanup();
return -1;
}
// 连接服务器
int sockfd = tcp_connect_server(IP_ADDRESS, PORT);
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);
// 创建线程发送数据
HANDLE hThread1 = CreateThread(NULL, 0, Fun1Proc, (void*)sockfd, 0, NULL);
CloseHandle(hThread1);
event_base_dispatch(base);
WSACleanup();
printf("finished \n");
return 0;
}
// 发送消息
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
char t_cin[1024];
int sockfd = (int)lpParameter;
while (1)
{
memset(t_cin, 0, 1024);
std::cin >> t_cin;
if (strcmp(t_cin, "exit") == 0)
{
break;
}
cmd_msg_cb(sockfd, t_cin);
}
exit(1);
return 0;
}
void cmd_msg_cb(int fd, char* msg)
{
int ret = send(fd, (const char*)msg, strlen((char*)msg), 0);
if (ret <= 0)
{
perror("read fail ");
return;
}
printf("send:%s\n", (char*)msg);
}
// 接收消息
void socket_read_cb(int fd, short events, void* arg)
{
char msg[1024];
// 为了简单起见,不考虑读一半数据的情况
int len = recv(fd, msg, sizeof(msg) - 1, 0);
if (len <= 0)
{
perror("read fail");
exit(1);
}
msg[len] = '\0';
printf("recv:%s\n", msg);
}
// 连接服务器
int tcp_connect_server(const char* server_ip, int port)
{
int sockfd, status, save_errno;
SOCKADDR_IN server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(server_ip);
server_addr.sin_port = htons(port);
sockfd = ::socket(PF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
return sockfd;
}
status = ::connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (status == -1)
{
save_errno = errno; // 清理
closesocket(sockfd);
errno = save_errno; // the close may be error
return -1;
}
evutil_make_socket_nonblocking(sockfd);
return sockfd;
}
本文向大家介绍一个C++实战项目:手把手教你了解并解决TCP粘包问题。通过该实战项目可以了解TCP粘包问题产生的原因及解决方式,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
本文向大家介绍一个C++实战项目:C++使用Websocket++实现WebSocket客户端通信,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
本文介绍一个C++代码片段:C++通过HTTP下载文件,感兴趣的朋友可以参考一下。
本文向大家介绍一个C++实战项目:libcurl实现上传文件支持中文路径,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
本文向大家介绍一个C++实战项目:C++多线程实现TCP服务器端同时和多个客户端通信。服务器同时可以和多个客户端建立连接,进行交互,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
本文向大家介绍一个C++实战项目:C++多线程实现并发TCP客户端测试程序。客户端支持同时自定义多个线程与服务端进行连接,并发发送数据,可用于测试服务端吞吐性能,具有一定的C++实战价值,感兴趣的朋友可以参考一下。