C语言写的UDP客户端收不到包
C-language written UDP client doesn't receive a packet
我正在用 C 写一个客户端-服务器程序。我无法处理这个问题:客户端向服务器发送消息,他收到消息并且一切正常,但是当服务器向客户端发送消息时,它不会捕获 UDP 数据包。服务器成功完成,而客户端一直在等待消息但没有收到消息。这是代码。
udpClient.c:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdlib.h>
#define BUF_SIZE 1024
#define BAD_EXIT_STATUS 1
void throw(int code, char * message) {
printf("%s\n", message);
exit(code);
}
char * readline(FILE * input) {
int size = 64;
char * line = malloc(size * sizeof(char));
char currentString[64];
while (1) {
fgets(currentString, sizeof(currentString), input);
if (strstr(currentString, "\n")) {
strcat(line, currentString);
break;
} else {
size += 64;
line = realloc(line, size * sizeof(char));
strcat(line, currentString);
}
}
return line;
}
typedef struct Args {
char* IP; // -a IP
int port; // -p port
} Args;
Args get_args(int argc, char **argv) {
Args args;
char * addr;
char * port;
if ((addr = getenv("L2ADDR"))) {
args.IP = addr;
} else {
args.IP = "127.0.0.1";
}
if ((port = getenv("L2PORT"))) {
args.port = atoi(port);
} else {
args.port = 1234;
}
int opt;
while((opt = getopt(argc, argv, "a:p:vh")) != -1) {
switch(opt) {
case 'a':
args.IP = optarg;
break;
case 'p':
args.port = atoi(optarg);
break;
case 'v':
printf("Lab2Server beta v.0.1.0\n");
exit(0);
case 'h':
printf("You can use: \n"
"\t-a [string] -- Sets ip address;\n"
"\t-p [string] -- Sets port;\n"
"\t-v -- Shows a version.\n");
exit(0);
default:
throw(BAD_EXIT_STATUS, "Use key -h to get some help.\n");
}
}
return args;
}
int main(int argc, char **argv){
Args args = get_args(argc, argv);
char c;
bool a = true;
int sockfd;
struct sockaddr_in serverAddr;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
throw(BAD_EXIT_STATUS, "Socket creation failed");
}
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(args.port);
serverAddr.sin_addr.s_addr = inet_addr(args.IP);
char buffer[BUF_SIZE];
printf("[Client]: ");
char *request = readline(stdin);
int n;
socklen_t len;
sendto(sockfd, (const char *) request, strlen(request), 0, (const struct sockaddr*)&serverAddr, sizeof(serverAddr));
printf("[+]Data Send: %s", buffer);
n = recvfrom(sockfd, (char *) buffer, BUF_SIZE, 0, (struct sockaddr *) &serverAddr, &len);
printf("[Server]: %s", buffer);
close(sockfd);
return 0;
}
udpServer.c:
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <math.h>
#include "utils.h"
#define BUF_SIZE 1024
#define ERROR_N_IS_BIG 1
#define ERROR_T_LESS_THAN_F 2
#define ERROR_N_IS_0 3
#define ERROR_NOT_ENOUGH_NUMBERS 4
int ds_size;
double *ds;
char *createResponse(char *buffer) {
return buffer;
}
int main(int argc, char **argv){
Args args = get_args(argc, argv); //прием аргов
FILE *output = fopen(args.logFile, "w+"); // запись логов
int sockfd; //для сокета
struct sockaddr_in serveraddr, cliaddr; //сокеты сервера и клиента
bool a = true;
//обработка ошибки создания сокета
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
throw(BAD_EXIT_STATUS, "Socket creation failed");
}
memset(&serveraddr, 0, sizeof(serveraddr)); //выделение памяти под СС
memset(&cliaddr, 0, sizeof(cliaddr)); // память под СК
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(args.port);
serveraddr.sin_addr.s_addr = inet_addr(args.IP);
if (bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) {
throw(BAD_EXIT_STATUS, "Bind failed");
}
if (args.isDaemon) {
pid_t process_id = 0;
process_id = fork();
if (process_id < 0) {
throw(BAD_EXIT_STATUS, "Fork failed!\n");
}
if (process_id > 0) {
printf("Server started with pid %d\n", process_id);
exit(0);
}
umask(0);
chdir("/");
if (setsid() < 0) {
throw(BAD_EXIT_STATUS, "Error on setsid()");
}
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
int n;
socklen_t len;
char buffer[BUF_SIZE];
n = recvfrom(sockfd, (char *)buffer, BUF_SIZE, MSG_WAITALL, (struct sockaddr*)& cliaddr, &len);
printf("[+]Data Received: %s", buffer);
char *hello = "Hello from server";
sendto(sockfd, (const char *) hello, strlen(hello), 0, (const struct sockaddr*)&cliaddr, sizeof(cliaddr));
printf("Hello message sent.\n");
return 0;
}
我还使用了下一个文件来制作程序 运行 和密钥
Utils.c
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "utils.h"
void throw(int code, char * message) {
printf("%s\n", message);
exit(code);
}
Args get_args(int argc, char **argv) {
Args args;
char * wait;
char * addr;
char * port;
char * logfile;
if ((wait = getenv("L2WAIT"))) {
args.waitFor = atoi(wait);
} else {
args.waitFor = 0;
}
if ((addr = getenv("L2ADDR"))) {
args.IP = addr;
} else {
args.IP = "127.0.0.1";
}
if ((port = getenv("L2PORT"))) {
args.port = atoi(port);
} else {
args.port = 1234;
}
if ((logfile = getenv("L2LOGFILE"))) {
args.logFile = logfile;
} else {
args.logFile = "/tmp/lab2.log";
}
args.isDaemon = false;
int opt;
while((opt = getopt(argc, argv, "w:dl:a:p:vh")) != -1) {
switch(opt) {
case 'w':
args.waitFor = atoi(optarg);
break;
case 'd':
args.isDaemon = true;
break;
case 'l':
args.logFile = optarg;
break;
case 'a':
args.IP = optarg;
break;
case 'p':
args.port = atoi(optarg);
break;
case 'v':
printf("Lab2Server beta v.0.1.0\n");
exit(0);
case 'h':
printf("You can use: \n"
"\t-w [int] -- Sets the delay;\n"
"\t-d -- Starts as daemon;\n"
"\t-a [string] -- Sets ip address;\n"
"\t-p [string] -- Sets port;\n"
"\t-l [string] -- Sets log file;\n"
"\t-v -- Shows a version.\n");
exit(0);
default:
throw(BAD_EXIT_STATUS, "Use key -h to get some help.\n");
}
}
return args;
}
double random_double(double min, double max) {
return (double)rand() / RAND_MAX * (max - min) + min;
}
void logMessage(FILE * output, struct sockaddr_in client_addr, char * message) {
time_t t = time(NULL);
char * ip = inet_ntoa(client_addr.sin_addr);
struct tm tm = *localtime(&t);
fprintf(output, "[%d-%02d-%02d %02d:%02d:%02d | %s]: %s", tm.tm_year + 1900, tm.tm_mon + 1,
tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ip, message);
fflush(output);
}
Utils.h
#include <netinet/in.h>
#ifndef UTILS_H
#define UTILS_H
#define BAD_EXIT_STATUS 1
typedef struct Args {
int waitFor; // -w N
bool isDaemon; // -d
char* logFile; // -l path
char* IP; // -a IP
int port; // -p port
} Args;
Args get_args(int, char**);
void throw(int, char*);
double random_double(double, double);
void logMessage(FILE *, struct sockaddr_in, char *);
#endif
这些程序是使用 Make 文件编译的:
.PHONY: build clean
udpServer: udpServer.o utils.o
gcc -o udpServer udpServer.o utils.o -lm
udpClient: udpClient.o
gcc -o udpClient udpClient.o
udpServer.o: udpServer.c
gcc -c -o udpServer.o udpServer.c -lm
udpClient.o: udpClient.c
gcc -c -o udpClient.o udpClient.c
utils.o: utils.c
gcc -c -o utils.o utils.c
clean:
rm -rf *.o
build:
make udpServer
make udpClient
make clean
所以当你完成文件后,你需要 运行 make build
来编译一个程序,然后你 运行 一个带有命令 ./udpServer -a 127.0.0.1 -p 1234
的服务器(在“ -a" 你可以 post 你想要的任何 IP 地址,在 "-p" 之后你 post 你想要的任何端口)并且在一个新的 window 你 运行 一个客户端使用命令./udpClient -a 127.0.0.1 -p 1234
(在“-a”之后你可以post你想要的任何IP地址,在“-p”之后你可以post你想要的任何端口)。
在文件 udpServer.c
中,函数 sendto()
使用了无效的 cliaddr
。为了获得正确的值,我们在调用 recvfrom()
.
之前初始化 len
socklen_t len = sizeof(struct sockaddr);
recvfrom(sockfd, (char *)buffer, BUF_SIZE, MSG_WAITALL, (struct sockaddr*)& cliaddr, &len);
recvfrom
的手册推荐
The argument addrlen is a value-result argument, which the caller should initialize before the call to the size of the buffer associated with src_addr and modified on return to indicate the actual size of the source address.
我正在用 C 写一个客户端-服务器程序。我无法处理这个问题:客户端向服务器发送消息,他收到消息并且一切正常,但是当服务器向客户端发送消息时,它不会捕获 UDP 数据包。服务器成功完成,而客户端一直在等待消息但没有收到消息。这是代码。
udpClient.c:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdlib.h>
#define BUF_SIZE 1024
#define BAD_EXIT_STATUS 1
void throw(int code, char * message) {
printf("%s\n", message);
exit(code);
}
char * readline(FILE * input) {
int size = 64;
char * line = malloc(size * sizeof(char));
char currentString[64];
while (1) {
fgets(currentString, sizeof(currentString), input);
if (strstr(currentString, "\n")) {
strcat(line, currentString);
break;
} else {
size += 64;
line = realloc(line, size * sizeof(char));
strcat(line, currentString);
}
}
return line;
}
typedef struct Args {
char* IP; // -a IP
int port; // -p port
} Args;
Args get_args(int argc, char **argv) {
Args args;
char * addr;
char * port;
if ((addr = getenv("L2ADDR"))) {
args.IP = addr;
} else {
args.IP = "127.0.0.1";
}
if ((port = getenv("L2PORT"))) {
args.port = atoi(port);
} else {
args.port = 1234;
}
int opt;
while((opt = getopt(argc, argv, "a:p:vh")) != -1) {
switch(opt) {
case 'a':
args.IP = optarg;
break;
case 'p':
args.port = atoi(optarg);
break;
case 'v':
printf("Lab2Server beta v.0.1.0\n");
exit(0);
case 'h':
printf("You can use: \n"
"\t-a [string] -- Sets ip address;\n"
"\t-p [string] -- Sets port;\n"
"\t-v -- Shows a version.\n");
exit(0);
default:
throw(BAD_EXIT_STATUS, "Use key -h to get some help.\n");
}
}
return args;
}
int main(int argc, char **argv){
Args args = get_args(argc, argv);
char c;
bool a = true;
int sockfd;
struct sockaddr_in serverAddr;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
throw(BAD_EXIT_STATUS, "Socket creation failed");
}
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(args.port);
serverAddr.sin_addr.s_addr = inet_addr(args.IP);
char buffer[BUF_SIZE];
printf("[Client]: ");
char *request = readline(stdin);
int n;
socklen_t len;
sendto(sockfd, (const char *) request, strlen(request), 0, (const struct sockaddr*)&serverAddr, sizeof(serverAddr));
printf("[+]Data Send: %s", buffer);
n = recvfrom(sockfd, (char *) buffer, BUF_SIZE, 0, (struct sockaddr *) &serverAddr, &len);
printf("[Server]: %s", buffer);
close(sockfd);
return 0;
}
udpServer.c:
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <math.h>
#include "utils.h"
#define BUF_SIZE 1024
#define ERROR_N_IS_BIG 1
#define ERROR_T_LESS_THAN_F 2
#define ERROR_N_IS_0 3
#define ERROR_NOT_ENOUGH_NUMBERS 4
int ds_size;
double *ds;
char *createResponse(char *buffer) {
return buffer;
}
int main(int argc, char **argv){
Args args = get_args(argc, argv); //прием аргов
FILE *output = fopen(args.logFile, "w+"); // запись логов
int sockfd; //для сокета
struct sockaddr_in serveraddr, cliaddr; //сокеты сервера и клиента
bool a = true;
//обработка ошибки создания сокета
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
throw(BAD_EXIT_STATUS, "Socket creation failed");
}
memset(&serveraddr, 0, sizeof(serveraddr)); //выделение памяти под СС
memset(&cliaddr, 0, sizeof(cliaddr)); // память под СК
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(args.port);
serveraddr.sin_addr.s_addr = inet_addr(args.IP);
if (bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) {
throw(BAD_EXIT_STATUS, "Bind failed");
}
if (args.isDaemon) {
pid_t process_id = 0;
process_id = fork();
if (process_id < 0) {
throw(BAD_EXIT_STATUS, "Fork failed!\n");
}
if (process_id > 0) {
printf("Server started with pid %d\n", process_id);
exit(0);
}
umask(0);
chdir("/");
if (setsid() < 0) {
throw(BAD_EXIT_STATUS, "Error on setsid()");
}
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
int n;
socklen_t len;
char buffer[BUF_SIZE];
n = recvfrom(sockfd, (char *)buffer, BUF_SIZE, MSG_WAITALL, (struct sockaddr*)& cliaddr, &len);
printf("[+]Data Received: %s", buffer);
char *hello = "Hello from server";
sendto(sockfd, (const char *) hello, strlen(hello), 0, (const struct sockaddr*)&cliaddr, sizeof(cliaddr));
printf("Hello message sent.\n");
return 0;
}
我还使用了下一个文件来制作程序 运行 和密钥
Utils.c
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "utils.h"
void throw(int code, char * message) {
printf("%s\n", message);
exit(code);
}
Args get_args(int argc, char **argv) {
Args args;
char * wait;
char * addr;
char * port;
char * logfile;
if ((wait = getenv("L2WAIT"))) {
args.waitFor = atoi(wait);
} else {
args.waitFor = 0;
}
if ((addr = getenv("L2ADDR"))) {
args.IP = addr;
} else {
args.IP = "127.0.0.1";
}
if ((port = getenv("L2PORT"))) {
args.port = atoi(port);
} else {
args.port = 1234;
}
if ((logfile = getenv("L2LOGFILE"))) {
args.logFile = logfile;
} else {
args.logFile = "/tmp/lab2.log";
}
args.isDaemon = false;
int opt;
while((opt = getopt(argc, argv, "w:dl:a:p:vh")) != -1) {
switch(opt) {
case 'w':
args.waitFor = atoi(optarg);
break;
case 'd':
args.isDaemon = true;
break;
case 'l':
args.logFile = optarg;
break;
case 'a':
args.IP = optarg;
break;
case 'p':
args.port = atoi(optarg);
break;
case 'v':
printf("Lab2Server beta v.0.1.0\n");
exit(0);
case 'h':
printf("You can use: \n"
"\t-w [int] -- Sets the delay;\n"
"\t-d -- Starts as daemon;\n"
"\t-a [string] -- Sets ip address;\n"
"\t-p [string] -- Sets port;\n"
"\t-l [string] -- Sets log file;\n"
"\t-v -- Shows a version.\n");
exit(0);
default:
throw(BAD_EXIT_STATUS, "Use key -h to get some help.\n");
}
}
return args;
}
double random_double(double min, double max) {
return (double)rand() / RAND_MAX * (max - min) + min;
}
void logMessage(FILE * output, struct sockaddr_in client_addr, char * message) {
time_t t = time(NULL);
char * ip = inet_ntoa(client_addr.sin_addr);
struct tm tm = *localtime(&t);
fprintf(output, "[%d-%02d-%02d %02d:%02d:%02d | %s]: %s", tm.tm_year + 1900, tm.tm_mon + 1,
tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ip, message);
fflush(output);
}
Utils.h
#include <netinet/in.h>
#ifndef UTILS_H
#define UTILS_H
#define BAD_EXIT_STATUS 1
typedef struct Args {
int waitFor; // -w N
bool isDaemon; // -d
char* logFile; // -l path
char* IP; // -a IP
int port; // -p port
} Args;
Args get_args(int, char**);
void throw(int, char*);
double random_double(double, double);
void logMessage(FILE *, struct sockaddr_in, char *);
#endif
这些程序是使用 Make 文件编译的:
.PHONY: build clean
udpServer: udpServer.o utils.o
gcc -o udpServer udpServer.o utils.o -lm
udpClient: udpClient.o
gcc -o udpClient udpClient.o
udpServer.o: udpServer.c
gcc -c -o udpServer.o udpServer.c -lm
udpClient.o: udpClient.c
gcc -c -o udpClient.o udpClient.c
utils.o: utils.c
gcc -c -o utils.o utils.c
clean:
rm -rf *.o
build:
make udpServer
make udpClient
make clean
所以当你完成文件后,你需要 运行 make build
来编译一个程序,然后你 运行 一个带有命令 ./udpServer -a 127.0.0.1 -p 1234
的服务器(在“ -a" 你可以 post 你想要的任何 IP 地址,在 "-p" 之后你 post 你想要的任何端口)并且在一个新的 window 你 运行 一个客户端使用命令./udpClient -a 127.0.0.1 -p 1234
(在“-a”之后你可以post你想要的任何IP地址,在“-p”之后你可以post你想要的任何端口)。
在文件 udpServer.c
中,函数 sendto()
使用了无效的 cliaddr
。为了获得正确的值,我们在调用 recvfrom()
.
len
socklen_t len = sizeof(struct sockaddr);
recvfrom(sockfd, (char *)buffer, BUF_SIZE, MSG_WAITALL, (struct sockaddr*)& cliaddr, &len);
recvfrom
的手册推荐
The argument addrlen is a value-result argument, which the caller should initialize before the call to the size of the buffer associated with src_addr and modified on return to indicate the actual size of the source address.