Server->Client 之间的 C++ Winsock 通信,反之亦然

Posted

技术标签:

【中文标题】Server->Client 之间的 C++ Winsock 通信,反之亦然【英文标题】:C++ Winsock communication between Server->Client and vice versa 【发布时间】:2012-02-28 16:24:26 【问题描述】:

我正在尝试在局域网上的程序之间制作一个简单的聊天程序。我的问题是我可以轻松地连接服务器并将消息从服​​务器发送到客户端,但反之则不行。我试图让它像这样工作。 ServerClient 就像在两个程序之间不断发送和接收一样,显然这需要一个循环来进行连续输入,但我不太确定该怎么做。这是服务器和客户端的代码。

//THIS IS THE SERVER 
    int main(int argc, char *argv[])

  WSADATA wsaData;
  int starterr = WSAStartup(MAKEWORD(2,2), &wsaData);
  if (starterr != 0) 
  
      cout << "WSADATA Failed to startup!" << endl;
      cout << "Error Code: " << WSAGetLastError() << endl;
      system("pause >nul");
      WSACleanup();
      return 0;
  

  cout << "WSADATA Startup Successful!" << endl;
  SOCKET mysock = socket(AF_INET, SOCK_STREAM, 0);
  if (mysock == INVALID_SOCKET)
  
      cout << "Socket Creation Failed!" << endl;
      cout << "Error Code: " << WSAGetLastError() << endl;
      system("pause >nul");
      WSACleanup();
      return 0;
  
  cout << "Socket Creation Successful!" << endl;
  sockaddr_in sin;
  sin.sin_port = htons(80);
  sin.sin_addr.s_addr = INADDR_ANY;
  sin.sin_family = AF_INET;
  if (bind(mysock,(sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
  
      cout << "Socket failed to bind!" << endl;
      cout << "Error Code: " << WSAGetLastError() << endl;
      system("pause >nul");
      WSACleanup();
      return 0;
  
  cout << "Socket Binded Successfuly!" << endl;

  //Listen to the socket until successful on receiving input
  while (listen(mysock, SOMAXCONN) == SOCKET_ERROR);
  SOCKET client;

  int lin = sizeof(sin);
  client = accept(mysock,(sockaddr*) &sin, &lin);
  cout << "Connection Established!" << endl;
  char buf[200] = "Message from server to client\n";


  //Send an initial message to the client 

  send(client, buf, sizeof(buf), 0);

  //but then how do I wait for a message from the client again here??
  //ive tried recv here before with no luck :/







  closesocket(mysock);
  closesocket(client);
  WSACleanup();
  system("pause >nul");    
  return 0;






   //Client program here
    int main(int argc, char *argv[])
    
      WSADATA wsaData;
      int starterr = WSAStartup(MAKEWORD(2,2), &wsaData);
      if (starterr != 0) 
      
          cout << "WSADATA startup has failed!" << endl;
          cout << "Error Code: " << WSAGetLastError() << endl;
          system("pause >nul");
          WSACleanup();
          return 0;
      
      cout << "WSADATA Startup Successful!" << endl;
      SOCKET mysock = socket(AF_INET, SOCK_STREAM, 0);

      if (mysock == INVALID_SOCKET)
      
          cout << "Socket Creation Failed!" << endl;
          cout << "Error Code:  " << WSAGetLastError() << endl;
          system("pause >nul");
          WSACleanup();
          return 0;
      

      cout << "Socket Creation Successful!" << endl;
      sockaddr_in sin;
      sin.sin_port = htons(80);
      sin.sin_addr.s_addr = inet_addr("127.0.0.1");//ip for connection
      sin.sin_family = AF_INET;
      if (connect(mysock,(sockaddr*)&sin, sizeof(sin)) == INVALID_SOCKET) 
      
          cout << "Socket Connection Failed" << endl;
          cout << "Error Code:  " << WSAGetLastError() << endl;
          system("pause >nul");
          closesocket(mysock);
          WSACleanup();
          return 0;
      
      cout << "Socket Has Connected Successfuly!" << endl;


      //Same applies here, receive message but exactly how do I send one back 

      char buf[200];
      recv(mysock, buf, sizeof(buf), 0);
      cout << buf;

      //send here seemed to bring up a bunch of symbols

      system("pause >nul");    
      WSACleanup();

      closesocket(mysock);

      return 0;
    

【问题讨论】:

【参考方案1】:

如果您想要全双工通信(即服务器端和客户端都能够随时发送和接收),您可以使用多个线程(我不建议这样做,因为多线程会引入竞争条件和死锁,除非您真的知道你在做什么),或者使用非阻塞 I/O,使用 select() 或 poll() 或类似的多路复用。使用多路复用,您基本上告诉 select()/poll() 调用“在发生有趣的事情之前不要返回”,其中“有趣的事情”定义为“数据到达套接字”,或者(如果您有数据要发送) “现在套接字上有可用的缓冲区空间来放置一些传出数据”。然后当 select()/poll() 返回时,检查哪些事件已被标记为就绪,适当调用 send()/recv()(这些调用永远不会阻塞,因为您将套接字设置为非阻塞-I /O 模式),然后在 select()/poll() 中再次进入睡眠状态,直到下一个事件发生。

通过这种方式,您的程序能够有效地处理 send() 和 recv(),无需旋转 CPU,也无需每次都使 recv() 延迟 send()(反之亦然)。

【讨论】:

我听从了您的建议并尝试了非阻塞 IO,我现在可以很好地工作了,感谢您的出色回答【参考方案2】:

看看这里: Client-Server communiation

但您还必须熟悉多线程,因为在这个链接示例中,您在客户端和服务器示例中有无限循环来侦听传入消息,因此您必须将它们放入线程中,您将能够发送和异步收听消息。如果您不将它们放入线程中,您将无法异步发送和接收消息,因为无限循环会阻止它们之外的所有操作。 我认为这是建立沟通最简单的方式。

【讨论】:

以上是关于Server->Client 之间的 C++ Winsock 通信,反之亦然的主要内容,如果未能解决你的问题,请参考以下文章

将 c++ unix server/socket 连接到 java windows client/socket

android binder 机制二(client和普通server)

如何使用 WebSocket 在 UWP Client 和 Java Server 之间进行通信?

jvm的client和server

INOTIFY监控服务与RSYNC服务实现CLIENT与SERVER之间的实时同步

在 node.js 上的 socket.io 上发送消息 client->server->client