Visual Studio中的套接字c ++应用程序无法通过两台计算机之间的以太网连接

时间:2018-03-02 20:07:43

标签: c++ windows sockets server client

我目前正在使用Visual Studio中使用C ++的简单服务器/客户端应用程序,通过以太网/ LAN电缆连接将消息从一台计算机发送到另一台计算机。我正在使用我在网上找到的客户端和服务器代码。

当我在同一台计算机上运行程序时,我可以从服务器接收消息。但是,如果我在一台计算机上运行客户端程序并在另一台计算机上运行服务器程序,则不会收到任何消息。

由于我只是使用以太网电缆在两台计算机之间进行通信,因此我将IP地址(从本地网络共享,适配器设置,TCP / IPv4)设置为特定于两台计算机,使服务器计算机为10.0。 1.2和客户端计算机是10.0.1.1,子网掩码均为255.255.255.0。然后,在代码中,我使用addr.sin_addr.s_addr = inet_addr("10.0.1.2")作为服务器,addr.sin_addr.s_addr = inet_addr("10.0.1.1")作为客户端。

但我仍然遇到从一台计算机向另一台计算机发送邮件的问题。

以下是代码:

/////////////////////Client Code///////////////////////////////

#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
#include <WinSock2.h>
#include <iostream>

int main()
{
  //Winsock Startup
  WSAData wsaData;
  WORD DllVersion = MAKEWORD(2, 1);
  if (WSAStartup(DllVersion, &wsaData) != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
  {
      MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);
      exit(1);
  }

  SOCKADDR_IN addr; //Address to be binded to our Connection socket
  int sizeofaddr = sizeof(addr); //Need sizeofaddr for the connect function
  addr.sin_addr.s_addr = inet_addr("10.0.1.1");
  addr.sin_port = htons(139); //Port = 139
  addr.sin_family = AF_INET; //IPv4 Socket

  SOCKET Connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //Set Connection socket
  if (connect(Connection, (SOCKADDR*)&addr, sizeofaddr) != 0) //If we are unable to connect...
  {
      MessageBoxA(NULL, "Failed to Connect", "Error", MB_OK | MB_ICONERROR);
      return 0; //Failed to Connect
  }
  std::cout << "Connected!" << std::endl;
  int rec = 0;
  char MOTD[256];
  while (1)
  {
      recv(Connection, MOTD, sizeof(MOTD), NULL); //Receive Message of the Day buffer into MOTD array
      std::cout << "MOTD:" << MOTD << std::endl;
      std::cout << "rec:" << rec << std::endl;
      rec++;
      Sleep(500);

  }
}

/////////////////////Server Code///////////////////////////////

#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)

#include <WinSock2.h>
#include <iostream>

int main()
{
    //WinSock Startup
    WSAData wsaData;
    WORD DllVersion = MAKEWORD(2, 1);
    if (WSAStartup(DllVersion, &wsaData) != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
    {
        MessageBoxA(NULL, "WinSock startup failed", "Error", MB_OK | MB_ICONERROR);
        return 0;
    }

    SOCKADDR_IN addr; //Address that we will bind our listening socket to
    int addrlen = sizeof(addr); //length of the address (required for accept call)
    addr.sin_addr.s_addr = inet_addr("10.0.1.2");
    addr.sin_port = htons(139); //Port
    addr.sin_family = AF_INET; //IPv4 Socket

    SOCKET sListen = socket(AF_INET, SOCK_STREAM, NULL); //Create socket to listen for new connections
    bind(sListen, (SOCKADDR*)&addr, sizeof(addr)); //Bind the address to the socket
    listen(sListen, SOMAXCONN); //Places sListen socket in a state in which it is listening for an incoming connection. Note:SOMAXCONN = Socket Oustanding Max Connections
    int counter = 0;
    SOCKET newConnection; //Socket to hold the client's connection
    newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen); //Accept a new connection
    if (newConnection == 0) //If accepting the client connection failed
    {
        std::cout << "Failed to accept the client's connection." << std::endl;
    }
    else //If client connection properly accepted
    {
        std::cout << "Client Connected!" << std::endl;
        while (counter <100)
        {
            char MD[256] = "Hi there."; //Create buffer with message 
            send(newConnection, MD, sizeof(MD), NULL); //Send MD buffer
            counter++;

        }

    }

    system("pause");
    return 0;
}

我真的不知道现在该做什么。我可以从一台计算机ping到另一台计算机,但我无法通过以太网连接将消息从一台计算机发送到另一台计算机。

2 个答案:

答案 0 :(得分:1)

主要问题是客户端连接到错误的IP。服务器的IP是10.0.1.2,但客户端正在尝试连接到10.0.1.1。这就是为什么它不适用于多台计算机。客户端需要连接到服务器的IP,而不是客户端的IP。

另外,你一般会犯其他几个错误。

在服务器端,您忽略了bind()listen()的返回值,accept()在错误而不是0时返回INVALID_SOCKET( - 1)。 / p>

在客户端,您忽略了recv()的返回值。它在错误时返回-1,在正常断开时返回0,并且&gt; 0表示实际读取的字节数。您需要注意这一点,尤其是当您将读取数据发送到std::cout时。您正在将char[]传递给operator<<,因此数据必须以空值终止,但recv()不能保证这一点。所以,要么:

  • 在阅读后,在char[]数据的末尾添加一个空终结符:

    int numRead = recv(Connection, MOTD, sizeof(MOTD)-1, NULL);
    if (numRead <= 0) break;
    MOTD[numRead] = 0; // <-- here
    std::cout << "MOTD:" << MOTD << std::endl;
    
  • char[]传递给std::cin.write()而不是operator<<,指定count参数中读取的实际字节数:

    int numRead = recv(Connection, MOTD, sizeof(MOTD), NULL);
    if (numRead <= 0) break;
    std::cout << "MOTD:";
    std::cout.write(MOTD, numRead); // <-- here
    std::cout << std::endl;
    

你的MOTD协议一般来说设计得不是很好。服务器为每条消息发送256个字节(如果幸运的话,send()可以发送更少的字节!),即使实际只使用了9个字节。所以你在浪费带宽。客户端希望每次都能接收到256个字节(这是不可保证的,因为recv()可能会收到更少的字节!)。更好的设计是让服务器发送在末尾具有终止分隔符的字符串,例如换行符或空终止符,然后让客户端在循环中读取,直到它接收到该分隔符,然后处理具有该分隔符的数据。已收到。

尝试更像这样的事情:

/////////////////////Client Code///////////////////////////////

#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)

#include <WinSock2.h>
#include <Windows.h>

#include <iostream>
#include <string>
#include <algorithm>

int main()
{
    //Winsock Startup
    WSAData wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 1), &wsaData);
    if (iResult != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
    {
        std::cout << "Winsock Startup Failed, Error " << iResult << std:endl;
        return 1;
    }

    SOCKADDR_IN addr = {};
    addr.sin_family = AF_INET; //IPv4 Socket
    addr.sin_addr.s_addr = inet_addr("10.0.1.2"); //Address to be connected to
    addr.sin_port = htons(139); //Port = 139

    SOCKET Connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //Create socket to establish new connection with
    if (Connection == INVALID_SOCKET)
    {
        iResult = WSAGetLastError();
        std::cout << "Failed to Create Socket, Error " << iResult << std::endl;
        WSACleanup();
        return 1; //Failed to Connect
    }

    if (connect(Connection, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) //If we are unable to connect...
    {
        iResult = WSAGetLastError();
        std::cout << "Failed to Connect, Error " << iResult << std::endl;
        closesocket(Connection);
        WSACleanup();
        return 1; //Failed to Connect
    }

    std::cout << "Connected!" << std::endl;

    int rec = 0;
    char buf[256], *ptr, *start, *end;
    int numRead;
    std::string MOTD;

    int iExitCode = 0;

    while (true)
    {
        numRead = recv(Connection, buf, sizeof(buf), NULL); //Receive data
        if (numRead == SOCKET_ERROR)
        {
            iResult = WSAGetLastError();
            std::cout << "Failed to Read, Error " << iResult << std:endl;
            iExitCode = 1;
            break;
        }

        if (numRead == 0)
        {
            std::cout << "Server disconnected!" << std::endl;
            break;
        }

        start = buf;
        end = buf + numRead;
        do
        {
            // look for MOTD terminator
            ptr = std::find(start, end, '\0');
            if (ptr == end)
            {
                // not found, need to read more...
                MOTD.append(start, end-start);
                break;
            }

            // terminator found, display current MOTD and reset for next MOTD...

            MOTD.append(start, ptr-start);

            std::cout << "MOTD:" << MOTD << std::endl;
            std::cout << "rec:" << rec << std::endl;

            rec++;
            MOTD = "";

            start = ptr + 1;
        }
        while (start < end);
    }

    closesocket(Connection);
    WSACleanup();

    return iExitCode;
}

/////////////////////Server Code///////////////////////////////

#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)

#include <WinSock2.h>
#include <Windows.h>

#include <iostream>
#include <string>

bool sendAll(SOCKET s, const void *buf, int size)
{
    const char *ptr = (const char*) buf;
    while (size > 0)
    {
        int numSent = send(s, ptr, size, NULL);
        if (numSent == SOCKET_ERROR) return false;
        ptr += numSent;
        size -= numSent;
    }
    return true;
}

int main()
{
    //WinSock Startup
    WSAData wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 1), &wsaData);
    if (iResult != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
    {
        std::cout << "WinSock Startup Failed, Error " << iResult << std::endl;
        return 1;
    }

    SOCKADDR_IN addr = {};
    addr.sin_family = AF_INET; //IPv4 Socket
    addr.sin_addr.s_addr = INADDR_ANY; //Address that we will bind our listening socket to. INADDR_ANY = all local IPv4 addresses
    addr.sin_port = htons(139); //Port

    SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //Create socket to listen for new connections
    if (sListen == INVALID_SOCKET)
    {
        iResult = WSAGetLastError();
        std::cout << "Failed to Create Socket, Error " << iResult << std::endl;
        closesocket(sListen);
        WSACleanup();
        return 1;
    }

    if (bind(sListen, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) //Bind the address to the socket
    {
        iResult = WSAGetLastError();
        std::cout << "Failed to Bind Socket, Error " << iResult << std::endl;
        closesocket(sListen);
        WSACleanup();
        return 1;
    }

    if (listen(sListen, SOMAXCONN) == SOCKET_ERROR) //Places sListen socket in a state in which it is listening for an incoming connection. Note:SOMAXCONN = Socket Outstanding Max Connections
    {
        iResult = WSAGetLastError();
        std::cout << "Failed to Listen, Error " << iResult << std::endl;
        closesocket(sListen);
        WSACleanup();
        return 1;
    }

    SOCKET newConnection; //Socket to hold the client's connection
    int iExitCode = 0;

    do
    {
        std::cout << "Waiting for Client to Connect..." << std::endl;

        int addrlen = sizeof(addr); //length of the address (required for accept call)

        newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen); //Accept a new connection
        if (newConnection == INVALID_SOCKET) //If accepting the client connection failed
        {
            iResult = WSAGetLastError();
            std::cout << "Failed to accept a client's connection, Error " << iResult << std::endl;
            iExitCode = 1;
            break;
        }

        std::cout << "Client Connected!" << std::endl;

        for (int counter = 0; counter < 100; ++counter)
        {
            std::string MOTD = "Hi there."; //Create buffer with message 

            if (!sendAll(newConnection, MOTD.c_str(), MOTD.length()+1))
            {
                iResult = WSAGetLastError();
                std::cout << "Failed to Send, Error " << iResult << std::endl;
                break;
            }
        }

        closesocket(newConnection);
        std::cout << "Client Disconnected!" << std::endl;
    }
    while (true);

    closesocket(sListen);
    WSACleanup();

    return iExitCode;
}

答案 1 :(得分:0)

感谢您的所有答案和评论!我通过更改端口号解决了问题。显然,一些端口号是保留的,所以我必须分配另一个。