英文:
C sockets on windows, randomly getting recv errors but errno is at 0?
问题
It appears that you have provided code for a client-server communication using sockets in a Windows environment. If you have any specific questions or need assistance with a particular part of this code, please feel free to ask.
英文:
I have a client and a server using sockets on windows. I start the server before the client, wait for it to hang and then start the client. Doing so, the call to recv()
will randomly (half of the time) return -1 and when I print errno it is at 0 (No Error)... The other half of the time it will receive the message and print it normally then close... Is there something wrong with this code ?
client.c
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <errno.h>
#define BUFFER_LEN 200
int main()
{
WSADATA WSAData;
WSAStartup(MAKEWORD(2,0), &WSAData);
SOCKET sock;
SOCKADDR_IN address;
// address.sin_addr.s_addr = inet_addr("127.0.0.1");
InetPton(AF_INET, "127.0.0.1", &address.sin_addr.s_addr);
address.sin_family = AF_INET;
address.sin_port = htons(8888);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
printf("Erreur lors de la création du socket. %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if ((connect(sock, (SOCKADDR *)&address, sizeof(address))) == -1) {
sprintf("Erreur lors de la connexion au socket. %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
char *msg = "Coucou\n";
printf("Envoi de coucou\n");
int bytesSent;
if ((bytesSent = send(sock, msg, strlen(msg), 0)) == -1) {
sprintf("Erreur lors l'envoi du message. %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("Bytes envoyés : %d\n", bytesSent);
WSACleanup();
return 0;
}
server.c
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define BACKLOG 3 // taille de la file d'attente
#define BUFFER_LEN 200 // taille du buffer de lecture
int main()
{
WSADATA WSAData;
WSAStartup(MAKEWORD(2,0), &WSAData);
SOCKET sockfd;
SOCKADDR_IN address;
// address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_family = AF_INET;
address.sin_port = htons(8888); // host to network short (conversion de host byte order en network byte order)
printf("Démarrage du serveur\n");
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
printf("Erreur lors de la création du socket. %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if ((bind(sockfd, (SOCKADDR *)&address, sizeof(address))) == -1) {
printf("Erreur lors de l'ouverture du socket. %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if ((listen(sockfd, BACKLOG)) == -1) {
printf("Erreur lors de l'écoute du socket. %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
SOCKET clientSocket;
SOCKADDR_IN clientAddress;
int addrLen = sizeof(clientAddress);
if ((clientSocket = accept(sockfd, (struct sockaddr *) &clientAddress, &addrLen)) == -1) {
printf("Erreur lors de l'acceptation de la connexion. %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// Convertion de l'IP en texte
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(clientAddress.sin_addr), ip, INET_ADDRSTRLEN);
printf("Connexion de %s:%i\n", ip, clientAddress.sin_port);
char buffer[BUFFER_LEN];
int len = recv(clientSocket, buffer, BUFFER_LEN, 0);
if (len == -1 && errno != EAGAIN) {
printf("Erreur lors de la réception du message. %s (%d)\n", strerror(errno), errno);
exit(EXIT_FAILURE);
} else if (len == 0) {
printf("Le client s'est déconnecté (extrémité de la socket fermée)\n");
exit(EXIT_FAILURE);
} else if (len > 0) {
printf("Message reçu : %s\n", buffer);
}
closesocket(clientSocket);
closesocket(sockfd);
WSACleanup();
return 0;
}
I also should mention that I compile with gcc main.c -lws2_32 -g -Wall
答案1
得分: 5
请注意,在客户端调用send()
后返回时,这并不意味着任何数据已发送到服务器。这只是表示数据已排队等待发送。
然后,您的客户端立即调用WSACleanup()
并退出。似乎这会立即销毁您的套接字,而在发送任何数据之前。
您应该在发送数据后和调用WSACleanup()
之间添加closesocket(sock)
。这将允许套接字以有序的方式关闭,包括刷新任何已排队等待发送的数据。
如@Hans所指出,读取errno
不是获取套接字错误的正确方法,您应该使用WSAGetLastError()。
英文:
The first thing to note is that when the call to send()
in your client returns, this does not mean that any data has been sent to your server. It just means the data has been queued up to be sent.
Your client then immediately calls WSACleanup()
and exits. It would appear that this just instantly destroys your socket, before it has had a chance to send anything.
You should add closesocket(sock)
between sending your data, and calling WSACleanup()
. This will allow the socket to be closed in an orderly manner, including flushing any data that has been queued up.
As pointed out by @Hans, reading errno
is not the correct way to get a socket error, you should use WSAGetLastError().
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论