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

一.概念:

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

 

二.UDP终端的编程

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

1.加载套接字

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

和TCP的加载套接字没区别

2.创建套接字

[html]  view plain copy print ?
  1. SOCKET sock;  
  2. unsigned long mode=1;//0:阻塞  
  3. int nRet;  
  4. sock=socket(AF_INET,SOCK_DGRAM,0);  

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

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

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

 

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

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

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

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

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

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

 

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

[html]  view plain copy print ?
  1. SOCKADDR_IN addrTo;  
  2. addrTo.sin_addr.S_un.S_addr=inet_addr(IP);//inet_addr将字符串ip转换成long型  
  3. addrTo.sin_family=AF_INET;  
  4. addrTo.sin_port=htons(Port);  
  5. sendto(sock,SendBuffer,sendBufLen,0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR));  

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值