WinSock2客户端/服务器通信:发送&收到字符串

时间:2015-08-13 03:01:53

标签: c++ string sockets

我在编写代码时遇到了一些困难,因为我不太了解。我有两个可以相互通信的PC的设置。它可以工作,但它只能发送单个字符。如果在没有IP地址参数的情况下执行命令,则一台PC就像服务器一样,另一台PC在给定服务器IP地址的情况下就像客户端一样连接到服务器。

代码全在这里:

$vars = array('12345:0','45678:0','78910:0','3434:1','2345:1');
$vacct = '';
foreach ($vars as $var)
{
    $vinfo = explode(":", $var);
    $vgroup = $vinfo[0];

    if($vacct != $vinfo[1])
    {
        switchAccount("details");
        $vacct = $vinfo[1];

    }
}

我想要实现的是能够发送字符串而不是单个字符。我希望它的工作方式是增加它发送的字节大小而不是当前的单字节。我假设它可以工作的方式,假设一次发送和接收总大小为64字节。

1 个答案:

答案 0 :(得分:0)

实际上你的问题区域实际上并不是很清楚。

我的解决方案如下。基本思想是分配相同大小的发送和接收缓冲区,将字符附加到键盘输入上的发送缓冲区,并在缓冲区满或用户点击返回键时传输缓冲区。

非阻塞send函数可能不会立即发送整个缓冲区(see the docs)。我决定继续阻止,直到整个缓冲区被发送,所以我不必跟踪单独的输入和传输缓冲区。你可以改进这一点,我敢肯定。

接收部分只回显接收到的任何字节。一般情况下,无法知道其他用户是否已“完成”发送数据,因此我们只需打印首次调用recv后收到的内容。

每次发送和接收后,我总是memset缓冲区为全零,以防止丢失空终止符的奇怪行为。简单地将空字符附加到当前字符串的末尾会更加优化,但有时我会变得偏执。

这是我的代码:

#define BUFFER_SIZE 64


void chat (int socket_d) 
{
  char sendBuffer[BUFFER_SIZE] = { 0 };
  char receiveBuffer[BUFFER_SIZE] = { 0 };
  int bufferPosition = 0;
  int charsSent = 0;
  int charsReceived = 0;
  while (true)
  {
    if (_kbhit ())
    {
      sendBuffer[bufferPosition++] = _getche();

      if (sendBuffer[bufferPosition - 1] == '\r' || bufferPosition == BUFFER_SIZE - 1)
      {
        // This defeats the purpose of a non-blocking socket, I know.
        // You can do better by keeping separate buffers for sending and
        // collecting input.
        while (charsSent < bufferPosition)
        {
          charsSent += send(
            socket_d,
            &sendBuffer[charsSent], // Treats the address of a character as a string.
            bufferPosition - charsSent, // Only send the part that hasn't been sent yet.
            0);
        }

        memset(sendBuffer, 0, bufferPosition); // Paranoid.
        bufferPosition = charsSent = 0;
        cout << "\n";
      }
    }

    charsReceived = recv (socket_d, receiveBuffer, BUFFER_SIZE, 0);
    if (charsReceived <= 0)
    {
      if (WSAGetLastError() != WSAEWOULDBLOCK) // A real problem - not just avoiding blocking.
      {
        cout << "Terminated " << WSAGetLastError() << "\n";
        return;
      }
    }
    else
    {
      cout << receiveBuffer;
      if (receiveBuffer[charsReceived - 1] == '\r')
        cout << "\n";
      memset(receiveBuffer, 0, charsReceived); // Super paranoid.
    }
  }
}

现在,在支持UTF-8或至少wchar_t之前,我不会真的认为这是“好”。 ASCII缺少很多人们希望能够在真实聊天应用程序中使用的字符。

PS - 根据Visual Studio 2013,不推荐使用inet_addr函数。我用inet_ptons代替了。 Here's the documentation on the Winsock implementation for it