简单的客户机/服务器TCP c++



我总是能够找到一种方法来修复我的代码,只是调试和浏览网页,但我现在被一些代码卡住了,我不知道我可以做什么样的测试来调试它。

基本上我试图在c++中实现一个简单的客户端/服务器关系,我注释了每一行,以确保我理解我在做什么,但仍然,它不起作用。

下面是我的客户端代码:

void startClient(){ 
int wsaStatus, connectStatus; //check errors
WSADATA WSAData;
wsaStatus=WSAStartup(MAKEWORD(2, 0), &WSAData);
if (wsaStatus != NO_ERROR) {
    std::cout << "WSA Startup failed with error : " << wsaStatus;
}
SOCKET sock; //defines the sockets TO SEND
SOCKADDR_IN sin;//information about the socket
sin.sin_addr.s_addr = inet_addr("127.0.0.1");//ip of the server you want to connect to
sin.sin_family = AF_INET;//family of the socket, for internet it's AF_INET
sin.sin_port = htons(1234);// 23 for telnet etc, it's the port
sock = socket(AF_INET, SOCK_STREAM, 0);//second parameter is the type of the socket, SOCK_STREAM opens a connection ( use for TCD ), SOCK_DGRAM doesn't connect() or accept() it's used for UDP
if (sock == INVALID_SOCKET) {
    std::cout << "INVALID SOCKET " << WSAGetLastError();
    WSACleanup();
}
bind(sock, (SOCKADDR *)&sin, sizeof(sin)); //binds the socket to the port and the adress above
char buffer[255]; //creates a buffer to receive messages
connectStatus=connect(sock, (SOCKADDR *)&sin, sizeof(sin)); //function to connect to the server
if (connectStatus == SOCKET_ERROR) { //it returns 0 if no error occurs
    std::cout << "Connection failed with error : " << WSAGetLastError();
    closesocket(sock);
    WSACleanup();
}
int iResult = send(sock, "Hello world!rn", 14, 0);
if (iResult == SOCKET_ERROR) {
    std::cout << "Send failed with error : " << WSAGetLastError() << std::endl;
}
closesocket(sock);
WSACleanup();
system("pause");

这是我的服务器代码:

void startServer(){
int wsaStatus; //check errors
WSADATA WSAData;
wsaStatus=WSAStartup(MAKEWORD(2, 0), &WSAData);
if (wsaStatus != NO_ERROR) {
    std::cout << "WSA Startup failed with error : " << wsaStatus;
}

SOCKET sock; //defines the sockets
SOCKADDR_IN sin; //information about the socket
sin.sin_addr.s_addr = htonl(INADDR_ANY); //since it's the server we accept any connection
sin.sin_family = AF_INET; //family of the socket, for internet it's AF_INET
sin.sin_port = htons(1234); // 23 for telnet etc, it's the port
sock = socket(AF_INET, SOCK_STREAM, 0); //second parameter is the type of the socket, SOCK_STREAM opens a connection ( use for TCD ), SOCK_DGRAM doesn't connect() or accept() it's used for UDP
if (sock == INVALID_SOCKET) {
    std::cout << "INVALID SOCKET " << WSAGetLastError();
    WSACleanup();
}
bind(sock, (SOCKADDR *)&sin, sizeof(sin)); //binds the socket to the port and the adress above
char buffer[255]; //to receive the messages
listen(sock, 1); //listens on the port of the socket, second parameter is the maximum of connections accepted
while (1)
{
    int sizeof_sin = sizeof(sin); //size of the socket used to take the information from the client connected
    sock = accept(sock, (SOCKADDR *)&sin, &sizeof_sin); //first parameter : socket, second parameter : client information socket, third parameter : size of the information about the socket
    std::cout << "Connection ok" << std::endl;
    if (sock != INVALID_SOCKET)
    {
        recv(sock, buffer, sizeof(buffer), 0);
        closesocket(sock);
        std::cout << buffer << std::endl;
    }
    else{
        std::cout << "ERROR" << std::endl;
    }
}

WSACleanup();

所以我首先启动服务器,它在accept()函数等待连接时停止,然后我启动客户端,成功发送消息,但服务器仍然等待accept()函数并且没有获得任何消息。

你可以看到我实现了很多错误检查,仍然没有帮助:')

干杯!

您正在尝试将客户端和服务器绑定到相同的端口,并且您没有检查bind的返回值是否存在错误。Bind会经常失败,因为另一个程序可能正在使用你想要的端口,所以它是一个你应该经常检查的返回值。

一般来说,客户端不需要绑定,除非你真的希望它有一个特定的本地端口,在大多数情况下,你不关心它使用的是哪个端口。服务器必须绑定,因为您确实需要知道端口才能进行连接。你不需要知道(通常)客户端端口。

同样,在服务器中,在调用accept时不应该重用sock变量。为accept的返回值创建一个新的套接字变量。现在,您的程序正在泄漏资源,因为您的listen套接字仍然打开,但您无法访问它,因为您覆盖了sock变量。

因为你使用的是Windows,一个很好的工具来帮助套接字程序是TCPView从SysInternals。它列出了系统上所有打开的套接字及其当前状态和传输的字节。

为什么在客户端代码中调用绑定 ?这是不必要的。Bind应该仅由服务器调用。TCP客户端将使用随机端口与服务器通信,因此不需要在客户端绑定。此外,来自两个不同进程的同一端口的绑定将失败,因为该端口已经在使用中。因此,请删除绑定并重新测试代码。

为了单独测试,您可以使用netcat工具。它是一个非常简单的工具,可以充当服务器或客户端: https://es.wikipedia.org/wiki/Netcat

因此,要测试客户端,只需在服务器模式下启动netcat,如下所示:
nc -l your_ip port

并启动您的客户端,因此您应该看到客户端正确地连接到已经启动的服务器。同样,您可以通过在客户端模式下启动nc来测试您的服务器。

此外,一旦启动服务器,您可以使用netstat(作为根用户)工具来确保服务器在正确的IP/端口上运行。因此,像下面这样的命令可以用来查看服务器的TCP套接字处于哪个状态(侦听等)。看看netstat的手册页,它是另一个非常有用的工具。

netstat -anp | grep your_port

使用netstat,您还可以看到客户端一旦连接到您的服务器和TCP连接的状态正在使用哪个端口。

相关内容

最新更新