Create TCP Echo Server using Libev

本文介绍如何使用Libev库编写一个简单的TCP回显服务器。该服务器能接受客户端连接,读取并回传接收到的消息。文章详细介绍了创建服务器套接字、监听连接请求、设置事件监听器及启动事件循环等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Libev provides APIs to write asynchronous socket programming. This article describes how to write a simple TCP echo server using libev.

Lets start to write simple asynchronous TCP echo server with the help of libev. The server accepts client connections, reads messages from connections and echo the same message back.

Steps to write TCP echo server:
  1. Create a server socket and bind to socket address
  2. Listen on server socket
  3. Create watcher to accept connection
  4. Write connection accept callback function
  5. Create and initialize watcher to read message from client
  6. Write callback function to read message
  7. Start event loop

1. Create a server socket and bind to socket address

First step is to create TCP internet socket and bind it to some port.
sd = socket(PF_INET, SOCK_STREAM, 0);

bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT_NO);
addr.sin_addr.s_addr = INADDR_ANY;

bind(sd, (struct sockaddr*) &addr, sizeof(addr));

2. Listen on server socket

To accept client connection, you need to start listing on server socket. Here we are using backlog of size 2.
listen(sd, 2);

3. Create watcher to accept connection

Now we accept client connection using 'accept' API. Before that, we create a watcher to keep watch on accept call. Initialize the watcher using server socket and connection accept callback function.
ev_io_init(&w_accept, accept_cb, sd, EV_READ);
ev_io_start(loop, &w_accept);

4. Write connection accept callback function

Write appropriate callback function to accept client connection.
void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
...
client_sd = accept(watcher->fd, (struct sockaddr *)&client_addr, &client_len);
...
}

5. Create and initialize watcher to read message from client

A new client socket is created on accepting the connection. To read messages from client, create a new watcher. Initialize it with client socket and read callback function.

w_client = (struct ev_io*) malloc (sizeof(struct ev_io));
...
ev_io_init(w_client, read_cb, client_sd, EV_READ);
ev_io_start(loop, w_client);

6. Write callback function to read message

Write appropriate read callback function to receive message from client and echo the same message back.
void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
...
read = recv(watcher->fd, buffer, BUFFER_SIZE, 0);
send(watcher->fd, buffer, read, 0);
...
}

7. Start event loop

Final step is to run infinite event loop to wait for events.

while (1)
{
ev_loop(loop, 0);
}

Now we have done with server code.

Here is the complete code for the server.

#include <stdio.h>
#include <netinet/in.h>
#include <ev.h>

#define PORT_NO 3033
#define BUFFER_SIZE 1024

int total_clients = 0;  // Total number of connected clients

void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents);
void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents);

int main()
{
struct ev_loop *loop = ev_default_loop(0);
int sd;
struct sockaddr_in addr;
int addr_len = sizeof(addr);
struct ev_io w_accept;

// Create server socket
if( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
{
  perror("socket error");
  return -1;
}

bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT_NO);
addr.sin_addr.s_addr = INADDR_ANY;

// Bind socket to address
if (bind(sd, (struct sockaddr*) &addr, sizeof(addr)) != 0)
{
  perror("bind error");
}

// Start listing on the socket
if (listen(sd, 2) < 0)
{
  perror("listen error");
  return -1;
}

// Initialize and start a watcher to accepts client requests
ev_io_init(&w_accept, accept_cb, sd, EV_READ);
ev_io_start(loop, &w_accept);

// Start infinite loop
while (1)
{
  ev_loop(loop, 0);
}

return 0;
}

/* Accept client requests */
void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_sd;
struct ev_io *w_client = (struct ev_io*) malloc (sizeof(struct ev_io));

if(EV_ERROR & revents)
{
  perror("got invalid event");
  return;
}

// Accept client request
client_sd = accept(watcher->fd, (struct sockaddr *)&client_addr, &client_len);

if (client_sd < 0)
{
  perror("accept error");
  return;
}

total_clients ++; // Increment total_clients count
printf("Successfully connected with client.\n");
printf("%d client(s) connected.\n", total_clients);

// Initialize and start watcher to read client requests
ev_io_init(w_client, read_cb, client_sd, EV_READ);
ev_io_start(loop, w_client);
}

/* Read client message */
void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents){
char buffer[BUFFER_SIZE];
ssize_t read;

if(EV_ERROR & revents)
{
  perror("got invalid event");
  return;
}

// Receive message from client socket
read = recv(watcher->fd, buffer, BUFFER_SIZE, 0);

if(read < 0)
{
  perror("read error");
  return;
}

if(read == 0)
{
  // Stop and free watchet if client socket is closing
  ev_io_stop(loop,watcher);
  free(watcher);
  perror("peer might closing");
  total_clients --; // Decrement total_clients count
  printf("%d client(s) connected.\n", total_clients);
  return;
}
else
{
  printf("message:%s\n",buffer);
}

// Send message bach to the client
send(watcher->fd, buffer, read, 0);
bzero(buffer, read);
}


Below is the complete code for basic client which connect to server and, send and receive message. You can also write your own client.
#include <stdio.h>
#include <netinet/in.h>

#define PORT_NO 3033
#define BUFFER_SIZE 1024

int main()
{
int sd;
struct sockaddr_in addr;
int addr_len = sizeof(addr);
char buffer[BUFFER_SIZE] = "";

// Create client socket
if( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
{
  perror("socket error");
  return -1;
}

bzero(&addr, sizeof(addr));

addr.sin_family = AF_INET;
addr.sin_port = htons(PORT_NO);
addr.sin_addr.s_addr =  htonl(INADDR_ANY);

// Connect to server socket
if(connect(sd, (struct sockaddr *)&addr, sizeof addr) < 0)
{
  perror("Connect error");
  return -1;
}

while (strcmp(buffer, "q") != 0)
{
  // Read input from user and send message to the server
  gets(buffer);
  send(sd, buffer, strlen(buffer), 0);

  // Receive message from the server
  recv(sd, buffer, BUFFER_SIZE, 0);
  printf("message: %s\n", buffer);
}

return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值