1. 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个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。
在使用TCP编写的应用程序与使用UDP编写的应用程序之间存在一些本质差异,其原因在于这两个传输层之间的差别:UDP是无连接不可靠的数据报协议,非常不同于TCP提供的面向连接的可靠字节流协议。然而,相比TCP,有些场合确实更适合使用UDP,典型应用程序又:DNS(域名系统)、NFS(网络文件系统)和SNMP(简单网络管理协议)。

2. UDP套接字编程

与面向连接的协议相比,面向无连接协议极为不同。其中一个重要的不同点就是客户端与服务器之间不必建立连接。
对于UDP套接字编程而言,服务器创建套接字后,调用bind()函数将套接字与准备接收数据的接口绑定在一起。和TCP编程不同的是,应用程序不必调用listen()和accept()函数等待客户端的连接。而只需要等待接收数据了。开发UDP套接字应用程序,有两个重要的函数sendto()和recvfrom()。服务器采用recvfrom()来接收来自客户端的数据报,并获得客户端的端地址,之后向客户端发送数据时,采用sendto()函数。
下图为UDP套接字编程流程图
从图示中可以明显的看出UDP套接字网络编程与TCP的区别。

3. UDP套接字函数

套接字创建socket()、地址绑定bind()函数与TCP套接字编程相同,具体请参考基本套接字编程(1) -- tcp篇,此处仅介绍消息传输函数sendto()与recvfrom();

3.1 消息发送函数sendto()

函数原型:
#include <sys/socket.h>
ssize_t sendto(int sockfd , const void *buf , size_t nbytes , int flags , const struct sockaddr *to , socklen_t addrlen);
<span style="white-space:pre"> </span>返回值:成功返回写的字节数,出错返回-1

函数说明:
sendto() 用来将数据由指定的socket传给对方主机。参数s为已建好连线的socket,如果利用UDP协议则不需经过连线操作。参数buf指向欲连线的数据内容,参数flags 一般设0,详细描述请参考send()。参数to用来指定欲传送的网络地址,结构sockaddr请参考bind()。参数addrlen为sockaddr的结构长度。
参数:

  • 前三个参数sockfd , buff 和 nbytes等同于read 和 write函数的三个参数:描述符、指向写出缓冲区的指针和写字节数;
  • falgs参数一般置0;
  • to参数指向一个含有数据报接收者的协议地址(如IP地址和端口号)的套接字地址结构,其大小由addrlen指定;
返回值:
若无错误发生,返回所发送数据的总数(请注意这个数字可能小于len中所规定的大小)。否则的话,返回SOCKET_ERROR错误(-1),应用程序可通过WSAGetLastError()获取相应错误代码。
  • WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup();
  • WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效;
  • WSAEACESS:要求地址为广播地址,但相关标志未能正确设置;
  • WSAEINTR:通过一个WSACancelBlockingCall()来取消一个(阻塞的)调用;
  • WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中;
  • WSAEFAULT:buf或to参数不是用户地址空间的一部分,或to参数太小(小于sockaddr结构大小);
  • WSAENETRESET:由于WINDOWS套接口实现放弃了连接,故该连接必需被复位;
  • WSAENOBUFS:WINDOWS套接口实现报告一个缓冲区死锁;
  • WSAENOTCONN:套接口未被连接;
  • WSAENOTSOCK:描述字不是一个套接口;
  • WSAEOPNOTSUPP:已设置了MSG_OOB,但套接口非SOCK_STREAM类型;
  • WSAESHUTDOWN:套接口已被关闭。一个套接口以1或2的how参数调用shutdown()关闭后,无法再用sned()函数;
  • WSAEWOULDBLOCK:套接口被标志为非阻塞, 但该调用会产生阻塞;
  • WSAEMSGSIZE:套接口为SOCK_DGRAM类型,且数据报大于WINDOWS套接口实现所支持的最大值;
  • WSAECONNABORTED:由于超时或其他原因引起虚电路的中断;
  • WSAECONNRESET:虚电路被远端复位;
  • WSAEADDRNOTAVAIL:所指地址无法从本地主机获得;
  • WSAEAFNOSUPPORT:所指定地址族中地址无法与本套接口一切使用;
  • WSAEDESADDRREQ:需要目的地址;
  • WSAENETUNREACH:当前无法从本主机联上网络;

3.2 消息接收函数recvfrom()

函数原型:
#include <sys/socket.h>
ssize_t recvfrom(int sockfd , const void *buf , size_t nbytes , int flags , const struct sockaddr *from, socklen_t addrlen);
返回值:成功返回写的字节数,出错返回-1

函数说明:

recvfrom()用来接收远程主机经指定的socket传来的数据,并把数据传到由参数buf指向的内存空间,参数nbytes为可接收数据的最大长度.参数,flags一般设0,其他数值定义参考recv(),参数from用来指定欲传送的网络地址,结构sockaddr请参考bind()函数,参数fromlen为sockaddr的结构长度。
参数说明:
  • 前三个参数sockfd , buff 和 nbytes等同于read 和 write函数的三个参数:描述符、指向写出缓冲区的指针和写字节数;
  • falgs参数一般置0;
  • from参数指向一个含有数据报接收者的协议地址(如IP地址和端口号)的套接字地址结构,其大小由addrlen指定;

返回值:

同sendto()函数!若无错误发生,返回所接收数据的总数(请注意这个数字可能小于len中所规定的大小)。否则的话,返回SOCKET_ERROR错误(-1),应用程序可通过WSAGetLastError()获取相应错误代码。
  • WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup();
  • WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效;
  • WSAEACESS:要求地址为广播地址,但相关标志未能正确设置;
  • WSAEINTR:通过一个WSACancelBlockingCall()来取消一个(阻塞的)调用;
  • WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中;
  • WSAEFAULT:buf或to参数不是用户地址空间的一部分,或to参数太小(小于sockaddr结构大小);
  • WSAENETRESET:由于WINDOWS套接口实现放弃了连接,故该连接必需被复位;
  • WSAENOBUFS:WINDOWS套接口实现报告一个缓冲区死锁;
  • WSAENOTCONN:套接口未被连接;
  • WSAENOTSOCK:描述字不是一个套接口;
  • WSAEOPNOTSUPP:已设置了MSG_OOB,但套接口非SOCK_STREAM类型;
  • WSAESHUTDOWN:套接口已被关闭。一个套接口以1或2的how参数调用shutdown()关闭后,无法再用sned()函数;
  • WSAEWOULDBLOCK:套接口被标志为非阻塞, 但该调用会产生阻塞;
  • WSAEMSGSIZE:套接口为SOCK_DGRAM类型,且数据报大于WINDOWS套接口实现所支持的最大值;
  • WSAECONNABORTED:由于超时或其他原因引起虚电路的中断;
  • WSAECONNRESET:虚电路被远端复位;
  • WSAEADDRNOTAVAIL:所指地址无法从本地主机获得;
  • WSAEAFNOSUPPORT:所指定地址族中地址无法与本套接口一切使用;
  • WSAEDESADDRREQ:需要目的地址;
  • WSAENETUNREACH:当前无法从本主机联上网络;

4. UDP回射程序实例

4.1 server.c

<pre name="code" class="cpp">#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/ip.h> const int SERV_PORT = 6000;
const int MAXLINE = 2048;
void dg_echo(int sockfd , struct sockaddr *pcliaddr , socklen_t clilen)
{
int n;
socklen_t len;
char mesg[MAXLINE];
for( ; ;)
{
len = clilen;
if((n = recvfrom(sockfd , mesg , MAXLINE , 0 , pcliaddr , &len))<0)
{
perror("recvfrom error");
exit(1);
}//if if((n = sendto(sockfd , mesg , n , 0 , pcliaddr , len)) < 0)
{
perror("sendto error");
exit(1);
}//if
}//for
}
int main(int argc , char **argv)
{
int sockfd;
struct sockaddr_in servaddr , cliaddr;
bzero(&servaddr , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
if((sockfd = socket(AF_INET , SOCK_DGRAM , 0)) < 0)
{
perror("socket error");
exit(1);
}//if if(bind(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)))
{
perror("bind error");
exit(1);
}//if
dg_echo(sockfd , (struct sockaddr *)&cliaddr , sizeof(cliaddr));
}

4.2 client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h> const int SERV_PORT = 6000;
const int MAXLINE = 2048; void dg_cli(FILE *fp , int sockfd , const struct sockaddr *pservaddr , socklen_t servlen)
{
int n;
char sendline[MAXLINE] , recvline[MAXLINE+1]; while(fgets(sendline , MAXLINE , fp) != NULL)
{
if(sendto(sockfd , sendline , strlen(sendline) , 0 , pservaddr , servlen) < 0)
{
perror("sendto error");
exit(1);
}//if if( ( n = recvfrom(sockfd , recvline , MAXLINE , 0 , NULL , NULL)) < 0)
{
perror("recvfrom error");
exit(1);
}//if
recvline[n] = '\0';
fputs(recvline , stdout);
}//while
} int main(int argc , char **argv)
{
int sockfd , t;
struct sockaddr_in servaddr;
if(argc != 2)
{
perror("usage: udpcli <IPaddress>");
exit(1);
}//if
bzero(&servaddr , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
if((t = inet_pton(AF_INET , argv[1], &servaddr.sin_addr)) <= 0)
{
perror("inet_pton error");
<span style="white-space:pre"> </span> exit(1);
}//if if((sockfd = socket(AF_INET , SOCK_DGRAM , 0)) < 0)
{
perror("socket error");
exit(1);
}//if dg_cli(stdin , sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr));
exit(0);
}

4.3 运行结果

基本套接字编程(7) -- udp篇的更多相关文章

  1. linux网络环境下socket套接字编程(UDP文件传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  2. 网络编程[第二篇]基于udp协议的套接字编程

    udp协议下的套接字编程 一.udp是无链接的    不可靠的 而上篇的tcp协议是可靠的,会有反馈信息来确认信息交换的完成与否 基于udp协议写成的服务端与客户端,各司其职,不管对方是否接收到信息, ...

  3. 探索UDP套接字编程

    UDP和TCP处于同一层网络模型中,也就是运输层,基于二者之上的应用有很多,常见的基于TCP的有HTTP.Telnet等,基于UDP有DNS.NFS.SNMP等.UDP是无连接,不可靠的数据协议服务, ...

  4. 【转】 探索UDP套接字编程

    UDP和TCP处于同一层网络模型中,也就是运输层,基于二者之上的应用有很多,常见的基于TCP的有HTTP.Telnet等,基于UDP有DNS.NFS.SNMP等.UDP是无连接,不可靠的数据协议服务, ...

  5. 基本套接字编程(3) -- select篇

    1. I/O复用 我们学习了I/o复用的基本知识,了解到目前支持I/O复用的系统调用有select.pselect.poll.epoll.而epoll技术以其独特的优势被越来越多的应用到各大企业服务器 ...

  6. C++网络套接字编程TCP和UDP实例

    原文地址:C++网络套接字编程TCP和UDP实例作者:xiaojiangjiang 1.       创建一个简单的SOCKET编程流程如下 面向有连接的套接字编程 服务器: 1)  创建套接字(so ...

  7. 【Python网络编程】利用Python进行TCP、UDP套接字编程

    之前实现了Java版本的TCP和UDP套接字编程的例子,于是决定结合Python的学习做一个Python版本的套接字编程实验. 流程如下: 1.一台客户机从其标准输入(键盘)读入一行字符,并通过其套接 ...

  8. linux网络编程-(socket套接字编程UDP传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  9. 基本套接字编程(1) -- tcp篇

    1. Socket简介 Socket是进程通讯的一种方式,即调用这个网络库的一些API函数实现分布在不同主机的相关进程之间的数据交换. 几个定义: (1)IP地址:即依照TCP/IP协议分配给本地主机 ...

随机推荐

  1. 使用CSS完美实现垂直居中的方法

    使用XHTML+CSS来实现元素的垂直居中一直是前端开发中的一个比较复杂且棘手的问题,作为网页设计师或前端开发工程师,这个垂直居中问题也是必须掌握的技巧之一,一些互联网公司面试题中也会出现这类题目.今 ...

  2. chrome浏览器调用 ajax 提示net::ERR_INCOMPLETE_CHUNKED_ENCODING问题解决方案,以及 Response.Close 和 Response.End 的一些问题。

    近段时间去了一家新公司任职,公司产品是一个网站,但是我发现它不兼容谷歌浏览器,用习惯了chrome的我简直是如鲠在喉.终于我抽出了时间,想纠正这个问题.F12一看,发现谷歌提示:net::ERR_IN ...

  3. DSP学习中遇到的几个问题(初级)

    1..c和.asm 文件分别为C语言和汇编语言的源文件. 2..cmd是存储器分配说明文件,主要功能是指定工程中的各段分配到那段存储器中,比如有片内RAM(起始地址,大小)和SDRAM等.这些要根据平 ...

  4. Unix调试工具dbx使用方法

     dbx 命令 用途 提供了一个调试和运行程序的环境. 语法 dbx [ -a ProcessID ] [ -c CommandFile ] [ -d NestingDepth ] [ -I Dire ...

  5. Emmet (Zen Coding) HTML基本语法

    1. 嵌套操作---------- 子操作: > div>ul>li   并列:+ div+ul>li   上级:^ ul>li^div   ul>li>a^ ...

  6. centos6.4安装Apache+MySQL+PHP

    一.安装 MySQL 首先来进行 MySQL 的安装.打开超级终端,输入: [root@localhost ~]# yum install mysql mysql-server 安装完毕,让 MySQ ...

  7. 修复 Firefox 下本地使用 Bootstrap 3 时 glyphicon 不显示问题

    本地开发使用 Firefox 调试,遇到了 glyphicon 图标不显示的问题,期初以为是路径问题,搜索一大圈后找到了答案,原来这是一个安全性的问题,于是问题就好办了,解决方案如下: 1. 在Fir ...

  8. MINA系列学习-IoAccpetor

    其实在mina的源码中,IoService可以总结成五部分service责任.Processor线程处理.handler处理器.接收器和连接器,分别对应着IoService.IoProcessor.I ...

  9. alphaRGB 转 RGB、16位

    struct xColor { BYTE b, g, r, a; }; struct RGBColor { BYTE b, g, r; }; //void operator <<(RGBC ...

  10. 读取XML 发送网页版邮件

    DataSet ds = new DataSet(); ds.ReadXml(AppDomain.CurrentDomain.BaseDirectory + "XML\\Mail.xml&q ...