WIN32汇编语言教程:第16章 TCP/IP和网络通信 · 16.4 UDP协议编程(1)
1. UDP协议的特征
虽然TCP协议由于可靠、稳定的特征而被用在大部分的应用场合,但是UDP由于对系统资源的要求比较小,所以也经常用在一些对数据的可靠性要求不高却要求效率的场所,如实时音频和视频点播等。
UDP协议是一个简单的面向数据报的传输层协议,它将进程需要发送的数据包加上UDP首部,封装成一个UDP数据报,然后传给Internet层的IP协议发送出去。UDP首部中只包括双方的端口号、数据包长度与校验和等很少的字段,所以UDP协议的效率是很高的。从这种意义上看,UDP协议很像“使用端口号进行复用的IP协议”。
UDP协议并不提供其他方式对数据的可靠性与有序性等进行控制,所以IP协议的传输特征几乎就是它的特征。UDP协议不是面向连接的,它在发送数据之前并不首先建立连接,所以无法确认对方是否在线,也无法确认对方的指定端口是否在监听中,它直接将数据报按照指定IP地址的指定端口发出去,如果对方不在线的话,数据就可能丢失。
UDP协议也不提供应答和重传机制,所以程序并不知道数据是否到达。同样,UDP协议也没有为数据包标识序号,所以数据到达对端的顺序有可能是不对的,相同的数据也有可能多次到达。它属于一种“发出就不管”的协议。
如果说TCP协议像是打电话,两个人在通话中实时控制通话的流程并保证内容的正确性,那么UDP协议就像是寄信,发信人虽然知道收信人的地址,但是他并不确定信件会不会安全抵达,也不知道收信人究竟有没有因为外出而收不到信。另外,如果发信人发了好几封信,这些信可能并没有按发信时的顺序到达。总之,在收到收信人的复信之前,发信人无法确定信件是否安全、无损和有序地到达。
但是在应用中,如果不需要很高的可靠性,使用UDP协议就非常适合,比如对于实时视频,如果因为途中丢了数据包导致中断了几分之一秒,最重要的不是将它补上而是保证下面播放的实时性,如果为了补上丢失的数据包而导致“停格”显然是不必要的。另外,像OICQ一类的软件使用的就是UDP协议,对于这些软件来说,丢失一两句聊天数据并不重要,重要的是减少服务器的开销以便为更多的客户端服务。
图16.12 UDP服务器/客户机模型
2. UDP程序的客户机/服务器模型
UDP协议通信双方的工作方式相对来说比较相似,对于一个UDP套接字来说,如果它已经被建立,那么不必经过连接的过程就可以直接发送数据。另外,UDP套接字无所谓是否进入“监听”状态,只要有数据发送到套接字对应的端口,它就可以被接收,所以类似TCP协议中的连接、监听和关闭等动作都是不存在的。
在UDP的通信双方中,首次通信的发起方必须知道对方的IP地址和UDP端口才可以发送数据。发起方的端口号不必固定,因为报文的IP首部和UDP首部中已经包括了自己的地址和端口号数据。接收方在以前不知道发送方地址的情况下也可以根据这个地址回复数据。
如图16.12所示,在UDP协议的服务器/客户机模型中,两端惟一的区别就是服务器端程序必须首先将套接字绑定到一个固定的端口,以便客户端能够向约定的端口发送数据。本节将使用一个UDP聊天室例子来说明如何在程序中使用UDP协议,这个例子实现了与前面的TCP聊天室几乎同样的功能。
16.4.1 UDP聊天室例子——客户端
UDP聊天室例子执行后的界面如图16.13所示,由于UDP协议并不需要连接的过程,所以和TCP聊天室的客户端相比,对话框中少了一个“连接”按钮,只要直接单击“发送”按钮,程序就按照上面输入的IP地址发送聊天语句。
图16.13 UDP聊天室例子的运行界面
UDP聊天室的例子代码在所附光盘的Chapter15\Chat-UDP目录中,其中的Client.asm和Client.rc文件是客户端的代码。资源文件Client.rc如下:
#include <resource.h>
#define ICO_MAIN 1000
#define DLG_MAIN 2000
#define IDC_SERVER 2001
#define IDC_INFO 2002
#define IDC_TEXT 2003
//####################################################################
ICO_MAIN icon "Main.ico"
//####################################################################
DLG_MAIN DIALOG 94, 83, 245, 153
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "UDP聊天-客户端"
FONT 9, "宋体"
{
LTEXT "服务器IP地址:", -1, 6, 6, 57, 8
EDITTEXT IDC_SERVER, 63, 4, 77, 12
EDITTEXT IDC_INFO, 4, 20, 237, 110, ES_MULTILINE | ES_AUTOVSCROLL
| ES_AUTOHSCROLL | ES_READONLY | WS_BORDER | WS_VSCROLL | WS_TABSTOP
LTEXT "输入", -1, 6, 138, 19, 8
EDITTEXT IDC_TEXT, 28, 136, 150, 12, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP
DEFPUSHBUTTON "发送(&S)", IDOK, 185, 135, 56, 14
}
UDP聊天室客户端的汇编源代码Client.asm内容如下:
.386
.model flat, stdcall
option casemap :none ; case sensitive
;####################################################################
; Include 数据
;####################################################################
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include wsock32.inc
includelib wsock32.lib
;####################################################################
; equ 数据
;####################################################################
DLG_MAIN equ 2000
IDC_SERVER equ 2001
IDC_INFO equ 2002
IDC_TEXT equ 2003
WM_SOCKET equ WM_USER + 100
UDP_PORT equ 9999
;####################################################################
; 数据段
;####################################################################
上页:第16章 TCP/IP和网络通信 · 16.3 TCP协议编程(7) 下页:第16章 TCP/IP和网络通信 · 16.4 UDP协议编程(2)