UDP传输就像发信件,发快递,无法确定对方收到,数据也可能丢。UDP即使对方不在线,也可以“正常”发送数据,即对于发送者来说是不care接收端是否在线的,如果对方不在线,那么数据就全丢了。
但是,UDP也有优点,比如:
1. 编程简单
2. UDP不进行流控制,不需要发送ACK应答,也不需要发送SEQ分配给数据包序列号,性能会高出TCP很多
所以在重视性能而不是可靠性的场合,例如实时性要求较高的视频音频传输,即便丢包也最多是画面抖动或杂音,速度才是最重要的,因此首选UDP。
UDP传输,无需在连接状态下进行,也就是说UDP编程中无需accept和listen这样的函数。
另外,只需创建一个UDP套接字就可以与多台主机通讯,即UDP**不面对连接**,不会保存之前的目标ip,也因此,每次发送数据都要输入目标IP。
TCP的发送端,在调用connect函数时,会自动分配IP和端口,但是UDP不需要connect,因此是在send函数调用时自动分配的。
bind函数不区分UDP和TCP,因此也可以通过bind函数强制指定。
从以下代码也可以看出,对于UDP传输,服务端实现和客户端实现是及其类似的。
客户端代码:
// tcpserverwin.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "stdafx.h"
#include
#include
#include
#pragma comment (lib,"ws2_32.lib")
#define BUF_SZ 30
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET svrSocket;
SOCKADDR_IN servAddr,clientAddr;
int strlen;
char message[BUF_SZ];
int szClientAddr;
if(argc!=3){
printf("usage : %s ip port\n",argv[0],argv[1]);
return 0;
}
if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0){
printf("WSAStartup failed\n");
return 0;
}
svrSocket = socket(PF_INET,SOCK_DGRAM,0);
if(svrSocket == INVALID_SOCKET){
printf("socket error\n");
return 0;
}
memset(&servAddr,0,sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(atoi(argv[1]));
//int bind(hSocket,(SOCKADDR*)&servAddr,sizeof(servAddr));
szClientAddr = sizeof(clientAddr);
for (;;)
{
fputs("insert message , q to quit\n",stdout);
fgets(message,BUF_SZ,stdin);
if(!strcmp(message,"q\n")){
break;
}
// 如果目标地址是固定的,这里可以不每次都指定目标地址,
// 在循环外使用connect函数绑定一下目标ip和端口号即可
memset(&clientAddr,0,sizeof(clientAddr));
clientAddr.sin_family = AF_INET;
clientAddr.sin_addr.s_addr = inet_addr(argv[1]);
clientAddr.sin_port = htons(atoi(argv[2]));
sendto(svrSocket,message,sizeof(message),0,
(SOCKADDR*)&clientAddr,sizeof(clientAddr));
strlen=recvfrom(svrSocket,message,BUF_SZ,0,
(SOCKADDR*)&clientAddr,&szClientAddr);
message[strlen] = 0;
printf("recv: %s\n",message);
}
closesocket(svrSocket);
WSACleanup();
return 0;
}
服务端代码:
// tcpserverwin.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "stdafx.h"
#include
#include
#include
#pragma comment (lib,"ws2_32.lib")
#define BUF_SZ 30
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET svrSocket;
SOCKADDR_IN servAddr,clientAddr;
int strlen;
char message[BUF_SZ];
int szClientAddr;
if(argc!=2){
printf("usage : %s port\n",argv[0]);
return 0;
}
if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0){
printf("WSAStartup failed\n");
return 0;
}
svrSocket = socket(PF_INET,SOCK_DGRAM,0);
if(svrSocket == INVALID_SOCKET){
printf("socket error\n");
return 0;
}
memset(&servAddr,0,sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(atoi(argv[1]));
//int bind(hSocket,(SOCKADDR*)&servAddr,sizeof(servAddr));
if(bind(svrSocket,(SOCKADDR*)&servAddr,sizeof(servAddr)) == SOCKET_ERROR){
printf("bind port [%d] error\n",atoi(argv[1]));
return 0;
}
szClientAddr = sizeof(clientAddr);
for (;;)
{
strlen=recvfrom(svrSocket,message,BUF_SZ,0,
(SOCKADDR*)&clientAddr,&szClientAddr);
sendto(svrSocket,message,strlen,0,
(SOCKADDR*)&clientAddr,sizeof(clientAddr));
}
closesocket(svrSocket);
WSACleanup();
return 0;
}