【发布时间】:2016-01-31 08:20:56
【问题描述】:
我有一个使用 UDP 的客户端和一个服务器: 客户端.c:
#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#define SERVER "127.0.0.1"
#define BUFLEN 512 //Max length of buffer
#define PORT 8888 //The port on which to send data
void die(char *s)
{
perror(s);
exit(1);
}
int main(void)
{
struct sockaddr_in si_other;
int s, i, slen=sizeof(si_other);
char buf[BUFLEN];
char message[BUFLEN];
if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
die("socket");
}
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);
if (inet_aton(SERVER , &si_other.sin_addr) == 0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
while(1)
{
printf("Enter message : ");
gets(message);
//send the message
if (sendto(s, message, strlen(message) , 0 , (struct sockaddr *) &si_other, slen)==-1)
{
die("sendto()");
}
//receive a reply and print it
//clear the buffer by filling null, it might have previously received data
memset(buf,'\0', BUFLEN);
//try to receive some data, this is a blocking call
if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen) == -1)
{
die("recvfrom()");
}
puts(buf);
}
close(s);
return 0;
}
当然还有我的服务器:
#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#define BUFLEN 512 //Max length of buffer
#define PORT 8888 //The port on which to listen for incoming data
void die(char *s)
{
perror(s);
exit(1);
}
int main(void)
{
struct sockaddr_in si_me, si_other;
int s, i, slen = sizeof(si_other) , recv_len;
char buf[BUFLEN];
//create a UDP socket
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
die("socket");
}
// zero out the structure
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
//bind socket to port
if( bind(s , (struct sockaddr*)&si_me, sizeof(si_me) ) == -1)
{
die("bind");
}
//keep listening for data
while(1)
{
printf("Waiting for data...");
fflush(stdout);
memset(buf,'\0',BUFLEN);
//try to receive some data, this is a blocking call
if ((recv_len = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen)) == -1)
{
die("recvfrom()");
}
//print details of the client/peer and the data received
printf("Received packet from %s:%d\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port));
printf("Data: %s\n" , buf);
//now reply the client with the same data
if (sendto(s, buf, recv_len, 0, (struct sockaddr*) &si_other, slen) == -1)
{
die("sendto()");
}
}
close(s);
return 0;
}
此代码运行良好。但是,我只想使用 UDP 发送一条消息。如果有一些变量,例如:int、int、string、int。如何隐藏到buf 以及更重要的 - 如何在服务器中接收变量?
【问题讨论】:
-
有几件事:首先不要使用
gets,它很危险并且自C99标准以来已被弃用并在C11标准中完全删除,请改用fgets。其次,你提供给recvfrom的地址结构长度是可以修改的,每次调用函数都需要设置。 -
至于您的问题,如果您想在主机之间发送不同的数据,那么您可能应该发明某种协议来告诉您发送什么类型的数据.使用具有固定标头的结构(包括数据包类型以及有效负载大小)是一种解决方案。
-
@JoachimPileborg - 你能举个例子(回答问题)应该如何看待来自客户端的最简单数据包和服务器中接收的数据。
-
不太好,TBH。它具有货物狂热的“memset”,假设传输总是文本,并且首先花费周期将接收缓冲区归零是确保空终止字符串的唯一方法:(
-
一种简单的方法是将变量编码为 ASCII 文本(例如使用 snprintf()),然后使用您已有的代码发送该文本。然后接收器需要解析接收到的 ASCII 文本以再次提取原始值(例如使用 atoi())。这将是一种序列化方法,正如 DavidSchwartz 所提到的,这正是您真正要问的。序列化是将数据转换为可以放入 UDP 数据包(或 TCP 流)的一系列字节,其对应物是反序列化,接收方将它们重新组合成数据。