UDP协议(用户数据报协议):
– 传输层协议
– 没有连接
– 不可靠
– 面向数据报
我们先创建一个简易的客户端和服务器。
服务器:
– socket:先创建一个套接字
– bind:将创建的套接字绑定到地址和端口上
– recvfrom:下面就以阻塞的方式等待客户端的数据
客户端:
– socket:先创建一个套接字
– sendto:和服务器进行通信
其中涉及到的函数如下:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
//domain:协议域,又称协议族(family)。常用的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域Socket)、AF_ROUTE等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
//type:指定Socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。流式Socket(SOCK_STREAM)是一种面向连接的Socket,针对于面向连接的TCP服务应用。数据报式Socket(SOCK_DGRAM)是一种无连接的Socket,对应于无连接的UDP服务应用。
//protocol:指定协议。常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
ssize_t sendto(int sock, void *buff, size_t nbytes, int flags,
struct sockaddr *to, socklen_t addrlen);
//sock:用于传输数据的UDP套接字文件描述符
//buff:保存待传输数据的缓冲地址值
//nbytes:待传输的数据长度,以字节为单位
//flags:可选参数,若没有则传递0
//to:存有目标地址信息的sockaddr结构体变量的地址值
//addrlen:传递给参数to的地址值结构体变量长度
ssize_t recvfrom(int sock, void *buff, size_t nbytes, int flags,
struct sockaddr *from, socklen_t *addrlen);
//sock:用于接收数据的UDP套接字文件描述符
//buff:保存接收数据的缓冲地址值
//nbytes:可接收的最大字节数
//flags:可选参数,若没有则传入0
//from:存有发送端地址信息的sockaddr结构体变量的地址值
//addrlen:保存参数from的结构体变量长度的变量地址值
server.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
int main(int argc,char* argv[])
{
if(argc != 3)//判断输入的格式
{
printf("please enter:[%s,ip,port].\n",argv[0]);
return 1;
}
//创建一个套接字
int sock = socket(AF_INET,SOCK_DGRAM,0);
if(sock < 0)
{
printf("socket error!\n");
return 2;
}
//因为我们采用的IPv4协议,所以得创建一个sockaddr_in的结构体来保存我们服务器的ip和端口信息
struct sockaddr_in lockal;
lockal.sin_family = AF_INET;//地址家族
lockal.sin_port = htons(atoi(argv[2]));//端口号(我们输入的是字符串,所以先转化为数字,然后在从网络转化为本地)
lockal.sin_addr.s_addr = inet_addr(argv[1]);//(点分十进制转化为四字节的)的ip地址
//将sock绑定ip和端口号
if(bind(sock,(struct sockaddr*)&lockal,sizeof(lockal)) < 0)
{
printf("bine error!\n");
return 3;
}
char buf[1024];
struct sockaddr_in client;//创建一个保存发送端的地址信息的sockaddr结构体
while(1)
{
socklen_t len = sizeof(client);
ssize_t s = recvfrom(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&client,&len);//接收消息,阻塞式
if(s > 0)
{
buf[s] = 0;//将最后一个置为0,这样防止读错
printf("[%s|%d]: %s\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port),buf);
}
}
}
client.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main(int argc,char* argv[])
{
if(argc != 3)//判断输入格式是否正确
{
printf("please enter:%s,ip,port.\n",argv[0]);
return(1);
}
//创建一个套接字
int sock = socket(AF_INET,SOCK_DGRAM,0);
if(sock < 0)
{
printf("socket error!\n");
return 2;
}
//保存服务器的地址信息
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);
char buf[1024];
while(1)
{
printf("Please enter:");
fflush(stdout);
ssize_t s = read(0,buf,sizeof(buf)-1);//从标准输入中读取数据
if(s > 0)
{
buf[s-1] = 0;
sendto(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&server,sizeof(server));//发送给服务器端
}
}
}
效果图:
服务器端:
[kaikai@localhost udp]$ ./server 192.168.43.146 8080
[192.168.43.146|57336]: 123
[192.168.43.146|57336]: 456
[192.168.43.146|57336]: 789
^C
[kaikai@localhost udp]$
客户端:
[root@localhost udp]# ./client 192.168.43.146 8080
Please enter:123
Please enter:456
Please enter:789
Please enter:^C
[root@localhost udp]#
由上面的结果我们可以了解到基于UDP网络编程的基本概念了吧。
版权声明:本文为q496958148原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。