C语言写的UDP客户端收不到包
Posted
技术标签:
【中文标题】C语言写的UDP客户端收不到包【英文标题】:C-language written UDP client doesn't receive a packet 【发布时间】:2020-04-05 12:37:47 【问题描述】:我正在用 C 编写一个客户端-服务器程序。我无法处理这个问题:客户端向服务器发送一条消息,他得到它并且一切正常,但是当服务器向客户端发送一条消息时,它没有't catch 一个 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-file 编译的:
.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”之后你可以发布任何你想要的 IP 地址,之后“-p”你发布你想要的任何端口)并在一个新窗口中你使用命令./udpClient -a 127.0.0.1 -p 1234
运行一个客户端(在“-a”之后你可以发布你想要的任何IP地址,在“-p”之后你可以发布任何你想要的端口)。
【问题讨论】:
发送方和接收方是否在同一台主机上运行? 当然!我使用相同的端口和 IP 地址 不确定是否有区别,但请尝试在服务器的sendto()
调用中使用len
而不是sizeof(cliaddr)
。
您没有发送空终止符,并且recvfrom()
不会用空值填充缓冲区,因此您无法使用%s
格式打印buffer
。
谢谢大家的回答!我会试试的!
【参考方案1】:
在文件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
的手册建议
addrlen 参数是一个值结果参数,调用者应该初始化 在调用之前 到与之关联的缓冲区的大小src_addr 并在返回时修改以指示源地址的实际大小。
【讨论】:
哦,谢谢它的工作,但它没有必要把 & 放在 len 之前(你把它放在第二行)。我擦掉了它,它起作用了。非常感谢!以上是关于C语言写的UDP客户端收不到包的主要内容,如果未能解决你的问题,请参考以下文章