繁体   English   中英

C++ 与 127.0.0.1 上的 Putty 客户端连接时 Winsock 库终止

[英]C++ Winsock Library Termination When connecting with Putty Client on 127.0.0.1

我正在尝试创建一个服务器客户端,一旦它工作,我可以将一个向量传递给它,并通过 ssh 像腻子一样将它发送到客户端程序。 问题是每当我尝试在 127.0.0.1:45000 上使用 putty 连接 raw 或 ssh 时,程序一旦连接就会终止。

这是我的代码:

#include <iostream>
#include <WS2tcpip.h>
#include <string>

#pragma comment (lib, "ws2_32.lib")

using namespace std;

void main()
{
    // Initialize winsock
    WSADATA wsData;
    WORD ver = MAKEWORD(2, 2);

    int wsOk = WSAStartup(ver, &wsData);
    if (wsOk != 0)
    {
        cerr << "Can't Intitialze winsock! Quiting" << endl;
        return;
    }

    // Create a socket to bind
    SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
    if (listening == INVALID_SOCKET)
    {
        cerr << "Can't create a socket! Quitting" << endl;
    }
    // Bind the socket to an ip address to the port
    sockaddr_in hint;
    hint.sin_family = AF_INET;
    hint.sin_port = htons(45000);
    hint.sin_addr.S_un.S_addr = INADDR_ANY; // could also use inet_pton

    bind(listening, (sockaddr*)&hint, sizeof(hint));

    // Tell winsock the socket is for listening
    listen(listening, SOMAXCONN);

    // Wait for connection
    sockaddr_in client;
    int clientSize = sizeof(client);

    SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);

    char host[NI_MAXHOST];  //Clients remote name
    char service[NI_MAXHOST]; // Service (port) the client is on

    ZeroMemory(host, NI_MAXHOST);
    ZeroMemory(service, NI_MAXHOST); // use mem set of linux

    if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
    {
        cout << host << " connected on port " << service << endl;
        return;
    }
    else
    {
        inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
        cout << host << " connected on port " <<
            ntohs(client.sin_port) << endl;
        return;
    }

    // Close listening socket
    closesocket(listening);
    // while loop; accept and echo message back to client
    char buf[4096];
    while (true)
    {
        ZeroMemory(buf, 4096);

        // wait for client to send data
        int bytesReceived = recv(clientSocket, buf, 4096, 0);
        if (bytesReceived == SOCKET_ERROR)
        {
            cerr << "Error in recv(). Quitting" << endl;
            break;
        }
        if (bytesReceived == 0)
        {
            cout << "Client Disconnected, bytes 0" << endl;
            break;
        }
        // echo message back to client
        send(clientSocket, buf, bytesReceived + 1, 0);

        // Close the socket

    }
    closesocket(clientSocket);


    // Shutdown winsock
    WSACleanup();
}

我正在编写它并在 Visual Studio 2019 中编译。

这是我在尝试连接 ssh 选项或 raw 时从 Putty 收到的消息。

尝试连接时出现 Puttys 错误的图片。

如果有人可以提供帮助,将不胜感激。 谢谢!

调用getnameinfo()时,无论getnameinfo()是成功还是失败,都会立即从main() return ,而无需先调用closesocket() 这是 Putty 错误的根源。 每当客户端连接时,您都会明确退出您的应用程序,而不会通知客户端连接正在关闭。

更一般地说,如果accept()成功(并且socket()也是),您应该始终在返回的SOCKET上调用closesocket() ,无论您的代码中发生什么其他事情(如果WSAStartup()成功,则与WSACleanup()相同)。

您的代码中还有其他几个错误:

  • main()具有非int返回类型是非法的(尽管一些编译器允许这样做,作为非标准扩展。不要依赖它。)。

  • 如果socket()失败,您将错过main()return

  • 您没有检查bind()listen()accept()send()上的错误。

  • 如果您只打算accept() 1 个客户端,那么将积压工作设置为SOMAXCONN是没有意义的。

  • 调用send()时可能存在缓冲区溢出。 想象一下,如果recv()正好返回接收到的 4096 个字节。 bytesReceived + 1个字节数发送回客户端将使 go 超出buf数组的范围。

话虽如此,尝试更像这样的东西:

#include <iostream>
#include <WS2tcpip.h>
#include <string>

#pragma comment (lib, "ws2_32.lib")

using namespace std;

int main()
{
    // Initialize winsock
    WSADATA wsData;
    WORD ver = MAKEWORD(2, 2);

    int errCode = WSAStartup(ver, &wsData);
    if (errCode != 0)
    {
        cerr << "Can't initialize winsock! Error " << errCode << ". Quitting" << endl;
        return 0;
    }

    // Create a socket to bind
    SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
    if (listening == INVALID_SOCKET)
    {
        errCode = WSAGetLastError();
        cerr << "Can't create listening socket! Error " << errCode << ". Quitting" << endl;
        WSACleanup();
        return 0;
    }

    // Bind the socket to an ip address to the port
    sockaddr_in hint = {};
    hint.sin_family = AF_INET;
    hint.sin_port = htons(45000);
    hint.sin_addr.s_addr = INADDR_ANY; // could also use inet_pton

    if (bind(listening, (sockaddr*)&hint, sizeof(hint)) == SOCKET_ERROR)
    {
        errCode = WSAGetLastError();
        cerr << "Can't bind listening socket! Error " << errCode << ". Quitting" << endl;
        closesocket(listening);
        WSACleanup();
        return 0;
    }

    // Tell winsock the socket is for listening
    if (listen(listening, 1) == SOCKET_ERROR)
    {
        errCode = WSAGetLastError();
        cerr << "Can't open listening socket! Error " << errCode << ". Quitting" << endl;
        closesocket(listening);
        WSACleanup();
        return 0;
    }

    // Wait for connection
    sockaddr_in client;
    int clientSize = sizeof(client);

    SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
    if (clientSocket == INVALID_SOCKET)
    {
        errCode = WSAGetLastError();
        cerr << "Can't accept a client! Error " << errCode << ". Quitting" << endl;
        closesocket(listening);
        WSACleanup();
        return 0;
    }

    char host[NI_MAXHOST];  //Clients remote name
    char service[NI_MAXHOST]; // Service (port) the client is on

    ZeroMemory(host, NI_MAXHOST);
    ZeroMemory(service, NI_MAXHOST); // use mem set of linux

    if (getnameinfo((sockaddr*)&client, clientSize, host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
    {
        cout << host << " connected on port " << service << endl;
    }
    else
    {
        inet_ntop(AF_INET, &(client.sin_addr), host, NI_MAXHOST);
        cout << host << " connected on port " << ntohs(client.sin_port) << endl;
    }

    // Close listening socket
    closesocket(listening);
    listening = INVALID_SOCKET;

    // while loop; accept and echo message back to client
    char buf[4096];
    while (true)
    {
        // wait for client to send data
        int bytesReceived = recv(clientSocket, buf, sizeof(buf), 0);
        if (bytesReceived == SOCKET_ERROR)
        {
            errCode = WSAGetLastError();
            cerr << "Error reading from client: " << errCode << ". Quitting" << endl;
            break;
        }

        if (bytesReceived == 0)
        {
            cout << "Client Disconnected" << endl;
            break;
        }

        // echo message back to client
        char *ptr = buf;
        int bytesToSend = bytesReceived;
        do
        {
            int bytesSent = send(clientSocket, ptr, bytesToSend, 0);
            if (bytesSent == SOCKET_ERROR)
                break;
            ptr += bytesSent;
            bytesToSend -= bytesSent;
        }
        while (bytesToSend > 0);

        if (bytesToSend != 0)
        {
            errCode = WSAGetLastError();
            cerr << "Error writing to client: " << errCode << ". Quitting" << endl;
            break;
        }
    }

    // Close the client socket
    closesocket(clientSocket);

    // Shutdown winsock
    WSACleanup();

    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM