是无连接的、不可靠的传输协议。采用UDP进行通信时,不需要建立连接,可直接向一个IP地址发送数据,但不但保证对方能否收到。网络上传输的是电信号,在传输过程中会有衰减,因此数据有可能在网络上就消失了;也有可能我们制定的IP地址还没有分配,或者分配的设备没有运行,导致数据接收不到。
UDP协议不需要建立连接,而且没有数据确认和重传机制,所以实时性很高。因此,在一些实时性要求较高的场合,例如视频会议,就可以采用UDP协议来实现。对于这些应用,丢失少量数据不会影响使用。
对于基于UDP的套接字编程,为什么仍然需要调用bind函数进行绑定呢?虽然面向无连接的socket编程无须建立连接,但是为了完成这次通信,对于接收端来说,它必须是先启动以接收客户端发送的数据,因此接收端必须告诉主机它是在那个地址和端口上等待数据的到来,也就是说,接收端必须调用bind函数将套接字绑定到一个本地地址和端口上。
-
WSAStartup函数
利用套接字编程时,第一步需要加载套接字库,通过WSAStartup函数来实现。该函数有两个功能:一是加载套接字库;二是进行套接字库的版本协商。函数声明如下:
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
wVersionRequested:
用来指定准备加载的Winsock库的版本。高位字节指定所需要的WinSock库的副版本,而低位字节则是主版本。可以通过MAKEWORD(x,y)宏(其中x是高位字节,y是低位字节)方便获取wVersionRequested值。
lpWSAData:
这是个返回值,指向WSADATA结构指针,WSAStartup函数用其加载的库版本有关的信息填在这个结构体中。
typedef struct WSAData{
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
}WSADATA, *LPWSADATA;
-
Socket函数
加载了套接字库后,就可以调用socket函数创建套接字了。函数声明如下:
SOCKET socket(int af, int type, int protocol);
af:指定地址族,对于TCP/IP协议的套接字,只能是AF_INET;
type:指定Socket类型;
protocol:与特定的地址家族相关的协议,如果指定为0,那么系统会根据地址格式和套接字类别,自动选择一个合适的协议。
如果socket函数调用成功,则返回一个新的SOCKET数据类型的套接字描述符;如果调用失败,这个函数就会返回一个INVALID_SOCKET值,错误信息可以通过WSAGetLastError函数返回。
-
bind函数
创建了套接字以后,应该将套接字绑定到本地的某个地址和端口上,这需要通过bind函数来实现。函数声明如下:
int bind(SOCKET s, const struct sockaddr FAR *name, int namelen);
s:指定要绑定的套接字;
name:指定了该套接字的本地地址信息,这是一个指向sockaddr结构的指针变量,随所使用的网路协议不同而不同;
namelen:该地址结构的长度;
struct sockaddr{
u_short sa_family;
char sa_data[14];
};
在TCP/IP的socket编辑过程中,可以使用sockaddr_in结构替换sockaddr,以方便我们填写地址信息。
sockaddr的结构体定义如下:
struct sockaddr_in{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
sockaddr_in成员sin_addr的类型in_addr,结构体定义如下:
struct in_addr{
union{
struct { u_char s_b1, s_b2, s_b3, s_b4;} S_un_b;
struct { u_short s_w1, s_w2; } S_un_w;
u_long S_addr;
}S_un;
}
-
sendto函数
Windows Socket的sendto函数将向一个特定的目的方发送数据,声明如下:
int sendto(SOCKET s, const char FAR* buf, int len, int flags,const struct sockaddr FAR * to, int tolen);
s:已建立的套接字;
buf:指向一个缓冲区,该缓冲区包含将要传递的数据;
len:缓冲区的长度;
flags:设置的值将影响函数的行为,一般设置为0;
to:是一个可选的指针,指定目标套接字地址;
tolen:to中指定的地址的长度;
-
recvfrom函数
Windows Socket的recvfrom函数将接收一个数据包信息并保存源地址。其原型声明如下所示:
int recvfrom(SOCKET s, const char FAR* buf, int len, int flags, struct sockaddr FAR* from, int FAR* fromlen);
s:建立连接之后准备接收数据的套接字;
buf:指向一个缓冲区,用来保存接收的数据;
len:缓冲区的长度;
flags:设置的值将影响函数的行为,一般设置为0;
from:是一个指向地址结构体的指针;
fromlen:整型指针,并且它是一个in/out类型的参数,表明在调用前需要给它指定一个初始值,当调用之后,会通过这个参数返回一个值,该返回值是地址结构的大小。