c++网络编程3:UDP编程

一.概念:

        UDP是传输层中面向无连接的协议,所以UDP丢包后是不会重传的,而且他在编程上服务端和客户端是没有区别的,有的只是“虚拟上”的服务端和客户端,他在编程的实现上也很简单,不像TCP那么复杂。

 

二.UDP终端的编程

      由于UDP在服务端和客户端是一样的,所以称为UDP终端,编程步骤如下:

1.加载套接字

WORD wVersionRequested;
wVersionRequested=MAKEWORD(1,1);//指定Winsock库的版本:1.1
WSADATA wsaData;
int err;
//使用WSAStartup加载套接字库,以及确定使用的套接字库的版本,这里使用的是1.1的版本
err=WSAStartup(wVersionRequested,&wsaData);
if(err!=0)
  return false;
if(LOBYTE(wsaData.wVersion)!=1||HIBYTE(wsaData.wVersion)!=1)
{
	//如果套接字库加载成功,但是版本不正确,那么调用WSACleanup	释放对套接字库的占用资源
	WSACleanup();
	return false;
}

和TCP的加载套接字没区别

2.创建套接字

SOCKET sock;
unsigned long mode=1;//0:阻塞
int nRet;
sock=socket(AF_INET,SOCK_DGRAM,0);

与TCP区别再与socket的第二个参数,这里是SOCK_DGRAM(数据式套接字),TCP的是SOCK_STREAM(流式套接字)

3.绑定套接字(这部是必须的,在终端开启端口)

//LPCTSTR在unicode环境下是const wchar *,非unicode环境下是const char *
//INADDR_ANY表示如果一台机器上(服务器)有多块网卡,每个网卡都有各自的IP,则INADDR_ANY
//会将套接字绑定到该机器上的所有网卡地址和端口上
SOCKADDR_IN addrSrv;
if(localIP==NULL)
	addrSrv.sin_addr.S_un.S_addr= htonl(INADDR_ANY);//由于这里需要网络字节序,所以将主机字节序转换成网络字节序
else
	addrSrv.sin_addr.S_un.S_addr=inet_addr(localIP);//inet_addr将字符串ip转换成long型
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(localPort);//由于这里需要网络字节序,所以将主机字节序转换成网络字节序
//下面的代码等效于这行代码return bind(hSocket,(SOCKADDR *)&addrSrv,sizeof(SOCKADDR))==0;
if(bind(sock,(SOCKADDR *)&addrSrv,sizeof(SOCKADDR))==0)
	return true;
else
	return false;

 

4.上面三步做完,就可以开启线程,在线程中使用recvfrom来接受数据(TCP使用的是recv)

RLen=recvfrom(sock,(char *)RecvBuffer,RecvBufferLen,0,(SOCKADDR *)&addrFrom,addrDataLen);
if(RLen<=0)
{
   int error=WSAGetLastError();
   TRACE("socket api error is %d\n",error);
}

RecvBuffer是接受到的数据,RecvBufferLen是需要一次接收的数据长度,RLen是实际接收的数据长度,addrFrom可以获取发送数据的UDP终端的地址和端口

注意: 虽然这里可以设置一次接收的数据长度RecvBufferLen,但是这个长度必须需要系统缓存的支持,系统有一个接收数据的缓存,这个缓存负责将网络传过来的数据放入其中,然后recv是从这个系统缓存取数据,系统默认的SOCKET接受缓存的大小为8688B(8.6K左右),如果sock函数recv或recvFrom从系统缓存中接受数据太慢,那么系统接受到新数据后就会将原缓存给覆盖了,这样在次调用recv函数就获取到了新数据,老数据就丢失了,这时候就要使用setsockopt方法将系统缓存开到32K最合适,如下:

if(setsockopt(sock,SOL_SOCKET,SO_RCVBUF,(const char *)&Max_RecvFrom_Buffer_Size,sizeof(int))!=0)
{
	//设置失败
	return INVALID_SOCKET;
}

Max_RecvFrom_Buffer_Size=32*1024B,在创建一个客户端的套接字之后就要使用setsockopt来设置系统缓存的大小了,也就是第2部做完后就要设置系统缓存

 

5.使用sendto来发送数据(TCP使用的是send)

SOCKADDR_IN addrTo;
addrTo.sin_addr.S_un.S_addr=inet_addr(IP);//inet_addr将字符串ip转换成long型
addrTo.sin_family=AF_INET;
addrTo.sin_port=htons(Port);
sendto(sock,SendBuffer,sendBufLen,0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR));

SendBuffer是发送的数据,sendBufLen是一次发送数据的长度,SOCKADDR_IN这个结构填入需要发送到的目的IP和端口,这里的发送长度要考虑网络最大的传输单元MTU=1500B,发送的数据长度控制在1400B较好。



 

 

 

 

 


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值