请问“linux的udp服务器select模式客户端和服务器无法通信”,如何解决
第一次学这段代码,有些不会的地方,请各位帮忙改正代码,感恩
问题
- 服务器无法接收客户端发送的数据
- 客户端一直显示Timeout
运行结果
服务器运行结果:
客户端运行结果:
服务器
代码如下
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/wait.h>
#define PORT 5001
#define Server_IP_ADDR "192.168.204.136"
#define BACKLOG 10
#define QUIT_CMD "quit"
#define SERV_RESP_STR "Server :"
void *handle_client_msg(void *arg) {
int new_fd = *(int *) arg;
printf("New client %d connected.\n", new_fd);
char buffer[BUFSIZ];
char resp_buffer[BUFSIZ + 10];
int ret;
while (1) {
bzero(buffer, BUFSIZ);
do {
ret = read(new_fd, buffer, BUFSIZ - 1);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
perror("read");
break;
}
if (!ret) {
printf("Client process has closed the connection.\n");
break;
}
printf("Received: %s\n", buffer);
bzero(resp_buffer, sizeof(resp_buffer));
snprintf(resp_buffer, sizeof(resp_buffer), "%s%s", SERV_RESP_STR, buffer);
do {
ret = write(new_fd, resp_buffer, strlen(resp_buffer));
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
perror("write");
break;
}
if (strlen(buffer) > strlen(SERV_RESP_STR) &&
!strncasecmp(buffer + strlen(SERV_RESP_STR), QUIT_CMD, strlen(QUIT_CMD))) {
printf("Client process %d has quit.\n", new_fd);
break;
}
}
close(new_fd);
free(arg);
return NULL;
}
void sig_child_handler(int signo) {
if (signo == SIGCHLD) {
while (waitpid(-1, NULL, WNOHANG) > 0);
}
}
int main(int argc, const char *argv[]) {
int sockfd;
struct sockaddr_in server_addr;
signal(SIGCHLD, sig_child_handler);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
exit(1);
}
int optval = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {
perror("setsockopt");
exit(1);
}
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
perror("bind");
exit(1);
}
if (listen(sockfd, BACKLOG) < 0) {
perror("listen");
exit(1);
}
printf("Server is Started.\n");
int new_fd;
pid_t pid;
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
while (1) {
new_fd = accept(sockfd, (struct sockaddr *) &client_addr, &client_addr_len);
if (new_fd < 0) {
perror("accept");
continue;
}
if ((pid = fork()) < 0) {
perror("fork");
close(new_fd);
} else if (pid == 0) {
close(sockfd);
char client_ip[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN)) {
perror("inet_ntop");
exit(1);
}
printf("Client IP: %s:%d\n", client_ip, ntohs(client_addr.sin_port));
handle_client_msg((void *) (intptr_t) new_fd);
exit(0);
} else {
close(new_fd);
}
}
close(sockfd);
return 0;
}
客户端
代码如下
补充说明:运行时需要三个参数:运行文件 服务器地址 服务器端口
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#define PORT 5001
#define Server_IP_ADDR "192.168.204.136"
#define BACKLOG 10
#define QUIT_CMD "quit"
#define SERV_RESP_STR "Server :"
void usage(const char *prog_name) {
printf("%s Usage: server_ip_addr port \n", prog_name);
printf("server_ip_addr: %s\n", Server_IP_ADDR);
printf("port: %d (>5000) \n\n", PORT);
}
int main(int argc, const char *argv[]) {
int sockfd = -1;
struct sockaddr_in server_addr;
int port = PORT;
if (argc != 3) {
usage(argv[0]);
exit(1);
}
port = atoi(argv[2]);
if (port <= 5000) {
usage(argv[0]);
exit(1);
}
// 创建socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
return 0;
}
// 准备服务器地址
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if (inet_pton(AF_INET, argv[1], &server_addr.sin_addr) != 1) {
perror("inet_pton");
close(sockfd); // 关闭套接字
exit(1);
}
printf("client is running...\n");
//非阻塞模式
fd_set rfds;
int maxfd = -1;
struct timeval timeout;
char buffer[BUFSIZ];
int result = -1;
while (1) {
FD_ZERO(&rfds);
FD_SET(0, &rfds);
FD_SET(sockfd, &rfds);
maxfd = sockfd > 0 ? sockfd : 0;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
int select_result = select(maxfd + 1, &rfds, NULL, NULL, &timeout);
if (select_result < 0) {
perror("select");
close(sockfd);
break;
} else if (select_result == 0) {
printf("Timeout, no data received.\n");
continue;
}
if (FD_ISSET(0, &rfds)) {// 标准键盘有输入
// 读取键盘输入至网络套接字fd
bzero(buffer, sizeof(buffer));
do {
result = read(0, buffer, BUFSIZ - 1);
} while (result < 0 && errno == EINTR);
if (result < 0) {
perror("read");
close(sockfd);
break;
}
if (!result) continue; // 未读取到数据
if (sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
perror("sendto");
close(sockfd);
break;
}
if (!strncasecmp(buffer, QUIT_CMD, strlen(QUIT_CMD))) {
printf("quit command received, exit...\n");
break;
}
}
if (FD_ISSET(sockfd, &rfds)) {// 服务器发送过来数据
// 读取网络套接字fd至标准输出
bzero(buffer, sizeof(buffer));
socklen_t addr_len = sizeof(server_addr);
do {
result = recvfrom(sockfd, buffer, BUFSIZ - 1, 0, (struct sockaddr *) &server_addr, &addr_len);
} while (result < 0 && errno == EINTR);
if (result < 0) {
perror("recvfrom");
continue;
}
if (!result) break; // 服务器关闭连接
printf("server: %s\n", buffer);
if (!strncasecmp(buffer, QUIT_CMD, strlen(QUIT_CMD))) {
printf("quit command received, exit...\n");
break;
}
}
}
// 关闭套接字
close(sockfd);
return 0;
}