echo服务器阻塞IO详解

服务器代码

这个写法的本质是一个客户端起一个线程,用了高级的C++11和智能指针,本质上可以改为低级的代码

#include <thread>
#include <string.h>

// a thread-per-connection current echo server
int main(int argc, char* argv[])
{
  InetAddress listenAddr(3007);
  Acceptor acceptor(listenAddr);
  printf("Accepting... Ctrl-C to exit\n");
  int count = 0;
  bool nodelay = argc > 1 && strcmp(argv[1], "-D") == 0;
  while (true)
  {
    TcpStreamPtr tcpStream = acceptor.accept();
    printf("accepted no. %d client\n", ++count);
    if (nodelay)
      tcpStream->setTcpNoDelay(true);

    // C++11 doesn't allow capturing unique_ptr in lambda, C++14 allows.
    std::thread thr([count] (TcpStreamPtr stream) {
      printf("thread for no. %d client started.\n", count);
      char buf[4096];
      int nr = 0;
      while ( (nr = stream->receiveSome(buf, sizeof(buf))) > 0)
      {
        int nw = stream->sendAll(buf, nr);
        if (nw < nr)
        {
          break;
        }
      }
      printf("thread for no. %d client ended.\n", count);
    }, std::move(tcpStream));
    thr.detach();
  }
}

客户端代码

命令行指定了发送字节数

#include "InetAddress.h"
#include "TcpStream.h"
#include <unistd.h>

int main(int argc, const char* argv[])
{
  if (argc < 3)
  {
    printf("Usage: %s hostname message_length [scp]\n", argv[0]);
    return 0;
  }

  const int len = atoi(argv[2]);

  InetAddress addr(3007);
  if (!InetAddress::resolve(argv[1], &addr))
  {
    printf("Unable to resolve %s\n", argv[1]);
    return 0;
  }

  printf("connecting to %s\n", addr.toIpPort().c_str());
  TcpStreamPtr stream(TcpStream::connect(addr));
  if (!stream)
  {
    perror("");
    printf("Unable to connect %s\n", addr.toIpPort().c_str());
    return 0;
  }

  printf("connected, sending %d bytes\n", len);

  std::string message(len, 'S');
  int nw = stream->sendAll(message.c_str(), message.size());
  printf("sent %d bytes\n", nw);

  if (argc > 3)
  {
    for (char cmd : std::string(argv[3]))
    {
      if (cmd == 's')  // shutdown
      {
        printf("shutdown write\n");
        stream->shutdownWrite();
      }
      else if (cmd == 'p') // pause
      {
        printf("sleeping for 10 seconds\n");
        ::sleep(10);
        printf("done\n");
      }
      else if (cmd == 'c') // close
      {
        printf("close without reading response\n");
        return 0;
      }
      else
      {
        printf("unknown command '%c'\n", cmd);
      }
    }
  }

  std::vector<char> receive(len);
  int nr = stream->receiveAll(receive.data(), receive.size());
  printf("received %d bytes\n", nr);
  if (nr != nw)
  {
    printf("!!! Incomplete response !!!\n");
  }
}

当发送数据量比较大的时候,这个程序会卡死,一直阻塞下去

所以不能简单使用阻塞IO读取数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
lwIP(Lightweight IP)是一个轻量级的开源TCP/IP协议栈,它被设计为可移植、可扩展和高度定制化,适用于各种嵌入式系统。其中,echo server是lwIP协议栈中比较基本的一个应用。 Echo server的作用是将接收到的数据原样返回给发送方。在lwIP中,echo server是由一个名为echod的应用程序实现的。下面,我将详细介绍lwIP echo server的实现流程。 1. 创建socket 首先,我们需要创建一个socket,用于监听客户端的连接请求。在lwIP中,socket是通过调用lwip_socket()函数创建的。例如: ``` int sock = lwip_socket(AF_INET, SOCK_STREAM, 0); ``` 其中,AF_INET表示IPv4地址族,SOCK_STREAM表示TCP协议。 2. 绑定IP地址和端口号 创建socket后,我们需要将其绑定到一个IP地址和端口号上,以便客户端能够连接到服务器。在lwIP中,可以通过调用lwip_bind()函数实现。例如: ``` struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(7); // Echo server默认端口号为7 addr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有网络接口 lwip_bind(sock, (struct sockaddr *)&addr, sizeof(addr)); ``` 其中,INADDR_ANY表示监听所有网络接口。 3. 监听连接请求 绑定端口号后,我们需要开始监听连接请求。在lwIP中,可以通过调用lwip_listen()函数实现。例如: ``` lwip_listen(sock, 5); // 允许同时连接的客户端数量为5 ``` 4. 接受连接 当有客户端连接到服务器时,我们需要接受连接请求,并创建一个新的socket用于与该客户端通信。在lwIP中,可以通过调用lwip_accept()函数实现。例如: ``` struct sockaddr_in client_addr; int client_sock = lwip_accept(sock, (struct sockaddr *)&client_addr, sizeof(client_addr)); ``` 5. 接收数据 当与客户端建立连接后,我们需要等待客户端发送数据。在lwIP中,可以通过调用lwip_read()函数实现。例如: ``` char buf[1024]; int len = lwip_read(client_sock, buf, sizeof(buf)); ``` 6. 发送数据 接收到客户端的数据后,我们需要将其原样返回给客户端。在lwIP中,可以通过调用lwip_write()函数实现。例如: ``` lwip_write(client_sock, buf, len); ``` 7. 关闭socket 当通信结束后,我们需要关闭与客户端建立的socket。在lwIP中,可以通过调用lwip_close()函数实现。例如: ``` lwip_close(client_sock); ``` 8. 释放资源 最后,我们需要释放创建的socket资源。在lwIP中,可以通过调用lwip_shutdown()函数实现。例如: ``` lwip_shutdown(sock, SHUT_RDWR); ``` 以上就是lwIP echo server的实现流程。需要注意的是,echod应用程序是在一个单独的线程中运行的,它不断地等待客户端的连接请求,并在接收到数据后将其原样返回给客户端。如果有多个客户端连接到服务器echod应用程序为每个客户端创建一个新的socket,从而实现多客户端同时连接的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值