我一直在做Winsock tutorials并完全遵循它。我无法让send()
或recv()
正常运作。我已经设置了基本的服务器和客户端程序,并且正在建立连接,但服务器没有向客户端发送消息。使用Telnet客户端也不会收到服务器的响应。我不确定发生了什么,我所看到的所有问题都不是基本的,或者有些东西我无法理解他们在做什么。
#include<WinSock2.h>
#include <io.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib") //winsock library
int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET s, new_socket;
sockaddr_in server, client;
int c;
char *message;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2), &wsa) != 0)
{
printf("Failed. Error Code : %d", WSAGetLastError());
return 1;
}
else
printf("Initialised.\n");
//create a socket
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
return 2;
}
else
printf("Socket created.\n");
//prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.S_un.S_addr = INADDR_ANY;
server.sin_port = htons(8888);
//bind the socket
if (bind(s, (sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : &d", WSAGetLastError());
return 3;
}
else
puts("Bind done");
//listen
listen(s, 3);
//accept an incoming connection
puts("Waiting for incoming connections...");
c = sizeof(sockaddr_in);
while (new_socket = accept(s, (sockaddr *)&client, &c) != INVALID_SOCKET)
{
printf("Connect successful...\n");
//reply to the client
message = "Hello Client, I have recieved your connection, but I have to go now, bye!\n";
send(new_socket, message, strlen(message), 0);
puts("Message sent.\n");
}
if (new_socket == INVALID_SOCKET)
{
printf("accept() failed with error code : %d", WSAGetLastError());
return 4;
}
//close the socket
closesocket(s);
WSACleanup();
return 0;
}
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <IPHlpApi.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
int main(int argc, char *argv[])
{
//intialize variables
WSADATA wsa;
char ip[100] = "192.168.1.117";
SOCKET s;
sockaddr_in server;
char *message, server_reply[75];
int recv_size;
//initialize Winsock
printf("\nInitialising Winsock...\n");
if(WSAStartup(MAKEWORD(2,2), &wsa) != 0)
{
printf("Failed. Error Code : %d", WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//create the socket
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
return 3;
}
printf("Socket created.\n");
server.sin_addr.S_un.S_addr = inet_addr(ip);
server.sin_family = AF_INET;
server.sin_port = htons(8888);
//connect to the server
if (connect(s, (sockaddr *)&server, sizeof(server)) < 0)
{
puts("connect error");
return 4;
}
else
{
printf("Connect successful");
recv_size = recv(s, server_reply, 75, 0);
}
if (recv_size <= 0)
{
puts("recv() failed\n");
}
else
{
//add a NULL terminating character to make it a proper string before printing
server_reply[recv_size] = '\0';
puts(server_reply);
}
getchar();
//close the socket
closesocket(s);
WSACleanup();
return 0;
}
客户也无法打印"recv() failed"
行;它就像卡在recv()
电话一样。
答案 0 :(得分:2)
在服务器端:
您没有检查listen()
的错误返回值。
您在c
的每次通话中都没有重置accept()
,并且您没有在接受的每个客户端上调用closesocket()
。
您没有检查send()
的错误返回值。
请改为尝试:
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib") //winsock library
int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET s, new_socket;
sockaddr_in server, client;
int c, res, messagelen;
const char *message;
printf("\nInitializing Winsock...");
res = WSAStartup(MAKEWORD(2,2), &wsa);
if (res != 0)
{
printf("Failed. Error: %d\n", res);
return 1;
}
printf("Initialized.\n");
//create a socket
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
printf("Could not create socket. Error: %d\n", WSAGetLastError());
return 2;
}
printf("Socket created.\n");
//prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.S_un.S_addr = INADDR_ANY;
server.sin_port = htons(8888);
//bind the socket
if (bind(s, (sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed. Error: &d", WSAGetLastError());
return 3;
}
printf("Bind done.\n");
//listen
if (listen(s, 3) == SOCKET_ERROR)
{
printf("Listen failed. Error: &d", WSAGetLastError());
return 4;
}
printf("Listening.\n");
//accept incoming connections
printf("Waiting for incoming connections...\n");
do
{
c = sizeof(sockaddr_in);
new_socket = accept(s, (sockaddr *)&client, &c);
if (new_socket == INVALID_SOCKET)
{
printf("Failed to accept a client. Error: %d\n", WSAGetLastError());
return 5;
}
printf("Client connected...\n");
//reply to the client
message = "Hello Client, I have received your connection, but I have to go now, bye!\n";
messagelen = strlen(message);
do
{
res = send(new_socket, message, messagelen, 0);
if (res == SOCKET_ERROR)
{
printf("Failed to send message. Error: %d\n", WSAGetLastError());
break;
}
message += res;
messagelen -= res;
}
while (messagelen > 0);
if (messagelen == 0)
printf("Message sent.\n");
//close the client socket
closesocket(new_socket);
}
while (true);
//close the server socket
closesocket(s);
WSACleanup();
return 0;
}
在客户端,我看到的唯一真正的问题是你的recv()
调用有一个潜在的缓冲区溢出等待发生,因为你要求它读取75个字节,这就是缓冲区的确切大小。只是发生了你的服务器最多只发送74个字节,但是如果它发送的更多,你可以在向它附加'\0'
终结符时溢出缓冲区。
所以,要么:
以recv()
作为缓冲区大小调用sizeof(server_reply)-1
,为添加的终结符留出空间:
recv_size = recv(s, server_reply, sizeof(server_reply)-1, 0);
使用printf()
代替puts()
,因此在将缓冲区打印到控制台时,根本不需要空终止缓冲区。您可以将recv_size
作为参数传递,以限制正在打印的文本数量:
//server_reply[recv_size] = '\0';
//puts(server_reply);
printf("%.*s", recv_size, server_reply);
答案 1 :(得分:0)
来自closesocket()的MSDN文档:
注意为了确保在连接上发送和接收所有数据,应用程序应在调用closesocket之前调用shutdown(有关详细信息,请参阅正常关闭,延迟选项和套接字关闭)。另请注意,在调用closesocket后,不会发布FD_CLOSE网络事件。
基本上,当您关闭套接字时,您发送的数据仍处于待处理状态。