人生是一座富矿,有待于自身去开采。 —— 崔鹤同
前面写了关于socket的TCP通信,今天介绍的是另一种无连接的通信方式,UDP通信。
UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768是UDP的正式规范。UDP在IP报文的协议号是17。
UDP协议全称是用户数据报协议 ,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天UDP仍然不失为一项非常实用和可行的网络传输层协议。
与所熟知的TCP(传输控制协议)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。UDP协议的主要作用是将网络数据流量压缩成数据包的形式。一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。
UDP和TCP编程的区别就在于使用的读写函数不同,因为UDP是无连接的,因此不使用connect函数,且读数据时可以用read或者recvfrom函数,但是写数据就只能用sento函数,因为read函数只能读数据,而不能读发送方的通信地址,而recvfrom两者皆可,UDP是点对点的模式,因此只是单纯的两者之间发送消息,互为服务器和客户端。
那么在编程前先介绍主要的两个函数:sendto和recvfrom函数
int sendto(int fd, void* addr, size_t len, int flag, struct sockaddr* addr, socklen_t addlen)
前三个参数和write的参数一样,flag给0即可,addr传入的是数据接收方的通信地址,addlen为通信地址的长度,成功返回发送的字节数,失败返回-1。
int recvfrom(int fd, void* data, size_t len, int flag, struct sockaddr* addr, socklen_t* addrlen)
前三个参数和read一样,flag给0即可,addr为传出参数,用于接收发送方的通信地址,addrlen是一个传入传出参数,传入addr的真实长度,传出接收到的客户端的通信地址的真实长度(同样这两个值一般是相同的)。
接下来说一说UDP编程的步骤:
先接收方:
1、socket
2、准备通信地址
3、bind
4、读写
5、关闭文件描述符
先发送方:
省掉bind即可
下面是UDP无连接的程序:
/*********************************************************************************
* Copyright: (C) 2017 tangyanjun<519656780@qq.com>
* All rights reserved.
*
* Filename: server.c
* Description: This file
*
* Version: 1.0.0(06/05/2017)
* Author: tangyanjun <519656780@qq.com>
* ChangeLog: 1, Release initial version on "06/05/2017 07:42:35 AM"
*
********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
int main(int argc, char **argv)
{
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1)
{
perror("socket");
exit(-1);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(2222);
addr.sin_addr.s_addr = inet_addr("10.154.216.80");
int res = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
if (res == -1)
{
perror("bind");
exit(-1);
}
printf("bind ok\n");
char buf[100] = {};
// res = read(fd, buf, sizeof(buf));
struct sockaddr_in from;
socklen_t len = sizeof(from);
res = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr*)&from, &len);
printf("读到了%d字节,内容:%s\n", res, buf);
sendto(fd, "welcome", 7, 0, (struct sockaddr*)&from, len);
close(fd);
return 0;
}
/*********************************************************************************
* Copyright: (C) 2017 tangyanjun<519656780@qq.com>
* All rights reserved.
*
* Filename: uclient.c
* Description: This file
*
* Version: 1.0.0(06/07/2017)
* Author: tangyanjun <519656780@qq.com>
* ChangeLog: 1, Release initial version on "06/07/2017 08:06:32 AM"
*
********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char **argv)
{
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1) perror("socket"), exit(-1);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(2222);
addr.sin_addr.s_addr = inet_addr("10.154.216.80");
sendto(fd, "hello", 5, 0, (struct sockaddr*)&addr, sizeof(addr));
char buf[100] = {};
read(fd, buf, sizeof(buf));
printf("%s\n", buf);
close(fd);
return 0;
}