【TCP/IP】多进程服务器的实现(进阶) - 用I/O分割优化回声客户端

      之前实现的回声客户端按照先向服务器端发送数据,直到服务器端收到回声数据后,再传输下一批数据。很大程度会影响端与端之间的数据交换效率(存在一个等待周期)。那么有什么办法可以解决这个问题呢?

I/O分割

        之前的回声客户端,采用的是单进程模式。我们不妨采用一种新的设计思路——用客户端的父进程接收数据,创建出子进程来发送数据,这样就可以使得同一客户端下不同进程分别去完成输入和输出操作。这样,无论服务器是否收到数据,都可以让客户端持续进行I/O操作。我们把这种处理方式称之为I/O分割。

        通过I/O分割,可以一定程度上提高频繁交换数据的程序的性能。因为分割I/O之后,发送数据时无需再去考虑接收数据的情况,使得程序能够连续发送数据,进而提高数据的吞吐量。(在网速较慢的情况下,做了I/O分割的程序性能一般远高于未做分割的)

代码实现

        知道了I/O分割的意义所在,那么接下来,让我们用I/O分割思想去实现对之前回声客户端的优化。

echo_mclient.cpp

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 1024

void Read_routine(int sock, char *buf);
void Write_routine(int sock, char *buf);
void Sender_message(char *message);

int main(int argc, char *argv[])
{
    int sock;
    int port;
    pid_t pid;
    std::string ipAddress;
    char buf[BUF_SIZE];
    struct sockaddr_in serv_adr;

    std::cout << "Please input IP and port that you want to connect:" << std::endl;
    std::cin >> ipAddress >> port;

    sock = socket(PF_INET, SOCK_STREAM, 0);
    if (sock == -1)
    {
        Sender_message((char *)"Socket creation error");
    }

    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = inet_addr(ipAddress.c_str());
    serv_adr.sin_port = htons(port);

    if (connect(sock, (struct sockaddr *)&serv_adr, sizeof(serv_adr)) == -1)
    {
        Sender_message((char *)"Connect error!");
    }
    // 创建子进程
    pid = fork();
    // 如果是子进程,那么进行写操作(发送数据);父进程则进行读操作(接收数据)
    pid == 0 ? Write_routine(sock, buf) : Read_routine(sock, buf);

    close(sock);
    return 0;
}

void Read_routine(int sock, char *buf)
{
    while (1)
    {
        int str_len = read(sock, buf, BUF_SIZE);
        if (str_len == 0)
        {
            return;
        }
        buf[str_len] = 0;
        printf("Message from server: %s", buf);
    }
}

void Write_routine(int sock, char *buf)
{
    while (1)
    {
        fgets(buf, BUF_SIZE, stdin);
        // 如果输入为q或Q,则关闭套接字写权限
        if (!strcmp(buf, "Q\n") || !strcmp(buf, "q\n"))
        {
            // 关闭套接字写权限
            shutdown(sock, SHUT_WR);
            return;
        }
        write(sock, buf, strlen(buf));
    }
}

void Sender_message(char *message)
{
    puts(message);
    exit(1);
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要使用 libevent 实现 TCP/IP 客户通信,可以按照以下步骤行: 1. 创建一个 event_base 对象,用于事件驱动循环。 2. 创建一个 TCP/IP 客户套接字,并连接到服务器。 3. 创建一个 bufferevent 对象,用于处理套接字的读写事件。 4. 设置 bufferevent 的回调函数,处理读写事件和错误事件。 5. 将 bufferevent 添加到 event_base 中,开始事件循环。 以下是一个简单的示例代码: ```c #include <event2/event.h> #include <event2/buffer.h> #include <event2/bufferevent.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> void read_cb(struct bufferevent *bev, void *ctx) { struct evbuffer *input = bufferevent_get_input(bev); char buf[1024]; size_t len = evbuffer_remove(input, buf, sizeof(buf)); // 处理接收到的数据 } void write_cb(struct bufferevent *bev, void *ctx) { // 数据已发送完成 } void error_cb(struct bufferevent *bev, short events, void *ctx) { if (events & BEV_EVENT_EOF) { // 连接已关闭 } else if (events & BEV_EVENT_ERROR) { // 发生错误 } else if (events & BEV_EVENT_TIMEOUT) { // 超时 } bufferevent_free(bev); } int main() { struct event_base *base = event_base_new(); int sockfd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in servaddr; servaddr.sin_family = AF_INET; servaddr.sin_port = htons(12345); inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); struct bufferevent *bev = bufferevent_socket_new(base, sockfd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, read_cb, write_cb, error_cb, NULL); bufferevent_enable(bev, EV_READ|EV_WRITE); event_base_dispatch(base); event_base_free(base); return 0; } ``` 在这个示例中,我们创建了一个 event_base 对象,一个 TCP/IP 客户套接字,并连接到服务器。然后创建了一个 bufferevent 对象,并设置了读写回调函数和错误回调函数。最后将 bufferevent 添加到 event_base 中,开始事件循环。在事件循环中,libevent 会自动处理套接字的读写事件和错误事件,调用相应的回调函数行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

干吃咖啡豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值