我有一个客户端和一个服务器在Windows上使用套接字。我在客户端之前启动服务器,等待它挂起,然后启动客户端。这样做,对recv()
的调用将随机(一半的时间)返回-1,当我打印errno时,它是0(无错误)...另一半时间它会收到信息并正常打印,然后关闭...这个代码有什么问题吗?
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;
}
我还应该提到我使用gcc main.c -lws2_32 -g -Wall
编译
1条答案
按热度按时间gab6jxml1#
首先要注意的是,当客户端返回对
send()
的调用时,这并不意味着任何数据已经发送到服务器。这只是意味着数据已经排队等待发送。然后,客户端立即调用
WSACleanup()
并退出。看起来这只是在它有机会发送任何东西之前立即破坏了你的插座。您应该在发送数据和调用
WSACleanup()
之间添加closesocket(sock)
。这将允许有序地关闭套接字,包括刷新已排队的任何数据。正如@Hans所指出的,阅读
errno
并不是获得套接字错误的正确方法,你应该使用WSAGetLastError()。