我为此创建了一个帐户,因为我在这里束手无策: 目标是让服务器接收并读取消息“Hello from client”中的 2 个字节 - 使用 recvfrom() 一次读取 1 个字节。 这是行不通的 - 第一个 recvfrom() 使程序无限期地休眠(我没有故意设置超时)。根据记录,我使用的是带有 Oracle VM VirtualBox 的 Linux (Ubuntu) 虚拟机,而且我对 C 编程相当陌生。 下面粘贴了 udp_server.c 和 udp_client.c 代码,希望有任何见解。
udp_server.c:
int main(void) {
/* Socket */
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
perror("socket(2)");
return 1;
}
/* Set socket option SO_REUSEADDR */
int opt = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
perror("setsockopt(2)");
close(sock);
return 1;
}
/* server sockaddr_in struct */
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_addr.s_addr = INADDR_ANY;
server.sin_family = AF_INET;
server.sin_port = htons(5061);
/* Bind */
if (bind(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
perror("bind(2)");
close(sock);
return 1;
}
/* client sockaddr_in struct (for recvfrom()) */
struct sockaddr_in client;
socklen_t client_len = sizeof(client);
memset(&client, 0, sizeof(client));
/* Receive data from socket */
fprintf(stdout, "Listening on port %d...\n", 5061);
char buffer[1024] = { 0 };
int bytes_received = recvfrom(sock, buffer, 1, 0, (struct sockaddr*)&client, &client_len);
// PROGRAM FREEZES HERE ^^^
if (bytes_received < 0) {
printf("bytes_received %d, errno %d", bytes_received, errno);
perror("recvfrom");
close(sock);
return 1;
}
printf("SUCCESS(1) bytes_received %d", bytes_received);
bytes_received = recvfrom(sock, buffer, 1, 0, (struct sockaddr*)&client, &client_len);
if (bytes_received < 0) {
printf("bytes_received %d, errno %d", bytes_received, errno);
perror("recvfrom");
close(sock);
return 1;
}
printf("SUCCESS(2) bytes_received %d", bytes_received);
/* Shutdown */
shutdown(sock, SHUT_RDWR);
close(sock);
return 0;
}
udp_client.c:
int main(void) {
/* Socket */
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) { // In case socket creation failed.
fprintf(stdout, "ERROR: Socket creation failed.\n");
return -1;
}
/* Server sockaddr_in struct (for sendto()) */
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(5061);
if (inet_pton(AF_INET, "127.0.0.1", &server.sin_addr) <= 0) {
perror("inet_pton(3)");
close(sock);
return 1;
}
/* Send data to socket */
char* message = "Hello from client";
int bytes_sent = sendto(sock, message, strlen(message), 0, (struct sockaddr*)&server, sizeof(server));
if (bytes_sent <= 0) {
perror("sendto(2)");
close(sock);
return 1;
}
fprintf(stdout, "Sent %d bytes to %s:%d - %s\n",
bytes_sent, inet_ntoa(server.sin_addr), ntohs(server.sin_port), message);
usleep(75000);
/* Shutdown */
shutdown(sock, SHUT_RDWR);
close(sock);
return 0;
}
udp_client
程序向udp_server
程序发送一个17字节的数据报,该程序需要两个各1字节的数据报。第一个数据报中多余的 16 个字节将被丢弃。
如果
udp_client
程序运行两次,那么两个17字节的数据报将被发送到udp_server
程序。每个接收到的数据报中多余的 16 个字节将被丢弃,因此 udp_server
会将以下内容写入标准输出流,作为读取两个数据报的结果:
Listening on port 5061...
SUCCESS(1) bytes_received 1SUCCESS(2) bytes_received 1
注意:输出后没有换行符。 “udp_server.c”中唯一在格式字符串末尾包含换行符的
printf
调用是打印 Listening on port 5061...
消息的调用。如果标准输出流是行缓冲,则其他printf
调用的输出将保持缓冲状态,直到程序退出,此时缓冲的内容将输出到终端。 Unix 中常见的 Unix 约定是将标准输入、标准输出和标准错误流初始化为“行缓冲”,除非已知这些流未连接到交互式设备(即终端),在这种情况下,标准输入和标准输出流可以完全缓冲。