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

时间:2015-10-01 12:11:00

标签: c++ sockets tcp server client

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

基本上我正在尝试在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!\r\n", 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()函数停止,然后启动成功发送消息的客户端但服务器仍在wait()函数等待并且没有得到任何消息。

正如您所看到的,我实施了大量错误检查,但仍无法帮助:')

干杯!

2 个答案:

答案 0 :(得分:1)

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

为了分别测试内容,您可以使用 netcat 工具。这是一个非常简单的工具,可以作为服务器或客户端:

https://es.wikipedia.org/wiki/Netcat

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

nc -l your_ip port

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

此外,启动服务器后,您可以使用 netstat (以root用户身份)工具确保服务器在正确的IP /端口上运行。因此,如下所示的命令可能有助于查看服务器的TCP套接字(监听等)的状态。看一下netstat的手册页,这是另一个非常有用的工具。

netstat -anp | grep your_port

使用netstat,您还可以看到客户端连接到服务器后使用的端口以及TCP连接的状态。

答案 1 :(得分:1)

您正在尝试将客户端和服务器绑定到同一个端口,并且在任何一种情况下都不会检查bind的返回值是否有错误。绑定是定期失败的,因为另一个程序可能正在使用你想要的端口,所以它应该总是检查它的返回值。

通常,客户端不需要绑定,除非您确实希望它具有特定的本地端口,并且在大多数情况下,您不关心它使用的端口。服务器必须绑定,因为您确实需要知道端口才能连接。您不需要知道(通常)客户端端口的任何内容。

此外,在服务器中,当您调用accept时,不应该重用sock变量。为accept的返回值创建一个新的套接字变量。现在,您的程序正在泄漏资源,因为您的侦听套接字仍处于打开状态,但由于您覆盖了sock变量,因此无法访问它。

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

相关问题