一.UDP协议
UDP是传输层的协议,它的主要作用是:将从网络中收到的数据,分配给具体的套接字的端口。UDP是一种不可靠的传输方式,提供的是不可靠的数据传输服务。
如果只考虑可靠性,TCP比UDP好,但 UDP在结构上比TCP更简洁。 UDP不会发送类似ACK的应答消息,也不会像SEQ那样给数据包分配序号。 因此,UDP的性能 有时比TCP高出很多。 在更重视性能而非可靠性的情况下,UDP是一种很好的选择。
TCP为了提供可靠的数据传输服务,TCP在不可靠的IP层进行流控制,而 UDP就没有这种流控制。 流控制 是区分UDP 和 TCP的最重要的标志。 TCP的生命在于流控制。 在收发数据量小但需要频繁连接时,UDP 比 TCP更高效。
二.数据IO函数
1.sendto 函数
#include<sys/socket.h>
ssize_t sendto( int sock , void* buf, size_t nbytes , int flags,
struct sockaddr* to, socklen_t addrlen);
成功时返回传输的字节数, 失败时返回 -1.
参数:
sock : 用于传输数据的UDP套接字文件描述符
buff: 保存待传输数据的缓冲地址值
nbytes: 待传输的数据长度,以字节为单位
flags: 可选项参数,若没有则传递0
to : 存有目标地址信息的sockaddr 结构体变量的地址值
addrlen: 传递给参数 to 的地址值的结构体变量长度
2. recvfrom函数
#include<sys/socket.h>
ssize_t recvfrom(int sock, void* buff, size_t nbytes, int flags,
struct sockaddr* from, socklen_t* addrlen);
成功时返回接受的字节数,失败时返回-1.
参数:
sock : 用于传输数据的UDP套接字文件描述符
buff: 保存待传输数据的缓冲地址值
nbytes: 可接收的最大字节数,无法超过参数buff所指的缓冲大小
flags: 可选项参数,若没有则传递0
to : 存有发送地址信息的sockaddr 结构体变量的地址值
addrlen: 保存参数 from 的结构体变量的变量地址值
三.代码实现
udp不同于tcp,不存在请求连接 和 受理过程,因此在某种意义上无法明确区分 服务器端和客户端。只是因其提供服务而称为服务器端。
运行过程中顺序并不重要,只需要保证在调用 sendto函数前, snedto 函数的目标主机程序已经开始运行。
1.server端:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/types.h>
#define BUF_SIZE 30
void error_handling(char* message);
int main(int argc , char* argv[])
{
int serv_sock;
char message[BUF_SIZE];
int str_len;
socklen_t clnt_adr_sz;
struct sockaddr_in serv_adr, clnt_adr;
if(argc!=2)
{
printf("Usage:%s<port>\n",argv[0]);
exit(1);
}
serv_sock = socket(PF_INET,SOCK_DGRAM,0);
if(serv_sock == -1)
{
error_handling("UDP socket creation error");
}
memset(&serv_adr,0,sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(argv[1]));
if(bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
error_handling("bind() error");
while(1)
{
clnt_adr_sz = sizeof(clnt_adr);
str_len = recvfrom(serv_sock,message,BUF_SIZE,0,(struct sockaddr*)&clnt_adr,&clnt_adr_sz);
message[str_len] = 0;
printf("Message from clinet:%s\n",message);
sendto(serv_sock,message,str_len,0,(struct sockaddr*)&clnt_adr,clnt_adr_sz);
}
close(serv_sock);
return 0;
}
void error_handling(char* message)
{
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
2.client 端:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/types.h>
#define BUF_SIZE 30
void error_handling(char* message);
int main(int argc, char* argv[])
{
int sock;
char message[BUF_SIZE];
int str_len;
socklen_t adr_sz;
struct sockaddr_in serv_adr,from_adr;
if(argc!=3)
{
printf("Usage:%s<IP><port>\n",argv[0]);
exit(1);
}
sock = socket(PF_INET,SOCK_DGRAM,0);
if(sock == -1)
error_handling("socket() error");
memset(&serv_adr,0,sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
serv_adr.sin_port = htons(atoi(argv[2]));
while(1)
{
fputs("Insert message(q to quit):",stdout);
fgets(message,sizeof(message),stdin);
if(!strcmp(message,"q\n")|| !strcmp(message,"Q\n"))
break;
sendto(sock,message,strlen(message),0,(struct sockaddr*)&serv_adr,sizeof(serv_adr));
adr_sz = sizeof(from_adr);
str_len = recvfrom(sock,message,BUF_SIZE,0,(struct sockaddr*)&from_adr,&adr_sz);
message[str_len]=0;
printf("Message from server:%s",message);
}
close(sock);
return 0;
}
void error_handling(char* message)
{
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}