我一直能够找到一种方法来修复我的代码只是调试和浏览网页,但我现在卡在一些代码上,我看不出我可以做什么样的测试来调试它。
基本上我正在尝试在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()函数等待并且没有得到任何消息。
正如您所看到的,我实施了大量错误检查,但仍无法帮助:')
干杯!
答案 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是一个帮助套接字程序的好工具。它列出了系统上所有打开的套接字及其当前状态和字节传输。