WinSock API实现UDP协议的详细代码

网络 网络管理
通过学习我们将要了解到UDP协议的基础知识以及WinSock API实现UDP协议的相关内容。那么我们也给出了具体的实施代码,希望对大家有所帮助。

UDP协议的使用在很多方面都可以实现。那么今天我们将要为大家介绍的就是WinSock API实现UDP的过程。首先来了解一下基本定义吧。UDP协议(User Datagram Protocol),即用户数据报协议,是定义用来在互连网络环境中提供包交换的计算机通信的协议。它是Internet上广泛采用的通信协议之一。UDP协议直接位于IP协议的顶层,属于传输层协议,它提供向另一用户程序发送信息的最简便的协议机制。

与TCP协议不同,UDP协议是一个无连接协议,发送端和接收端不建立连接;UDP协议不提供数据传送的保证机制,可以说它是一种不可靠的传输协议;UDP协议也不能确保数据的发送和接收顺序,实际上,这种乱序性很少出现,通常只是在网络非常拥挤的情况下才可能发生。既然UDP协议有着如此多的缺点,那么它存在的意义何在?其实正是由于UDP协议的这些缺点,才使得它具有许多TCP协议所望尘莫及的优势。TCP协议植入的各种安全保障功能加大了执行过程中的系统开销,使速度受到严重的影响;而UDP不提供信息可靠传递机制,将安全和排序等功能移交给上层应用来完成,极大地提高了执行速度。UDP协议执行速度快,适合视频、音频、文件等大规模数据的网络传输。

尽管UDP协议与TCP协议存在着巨大的差异,但程序设计的基本步骤还是差不多的。UDP协议不存在TCP协议中的服务端和客户端之分,相对于TCP协议的C/S模型,UDP协议的通信模型更为对称。在UDP协议网络通信中,根据功能的不同,可以划分为发送端和接收端,但这种划分是一种动态的划分,而不是绝对的,同一个套接字在某一时刻发送数据,那么就是发送端,而在另一时刻接收数据,那么就是接受端。也就是说,同一套接字既可以是发送端也可以是接收端。另外,前面提到了UDP协议是一个无连接协议,这就是说,我们在编写基于UDP协议的网络通信程序时,不需要监听端口、请求连接、接受连接请求和断开连接。

UDP协议的对称性和无连接特性就决定了实现基于UDP协议的网络通信比实现基于TCP协议的网络通信在程序设计上要简单得多。但是,在实际应用中,由于UDP协议的不可靠性和无序性,往往需要由上层应用来完成安全和排序等功能。

以下将给出利用WinSock API实现基于UDP协议的网络编程的具体步骤和源代码。

(1) 初始化通信端口。

可以在程序向导中添加Windows Sockets支持,或者直接添加代码:

#include <afxsock.h>
if (!AfxSocketInit())
{
AfxMessageBox("Windows 通信端口初始化失败!");
} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

#p#(2) 实现UDP协议。

初始化Windows Sockets DLL。目前WinSock API有两个版本,版本号分别为1.1和2.2,对应参数为0x101和0x202。

WSADATA wsaData;
if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0)
{
AfxMessageBox("加载Windows Sockets DLL失败!");
WSACleanup();
} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

(3) 创建流式套接字。

请注意socket()函数的第二个参数相对于ICP协议有什么变化。套接字族:

AF_UNIX: UNIX内部协议族 
AF_INET: Iternet协议 
AF_NS: XeroxNs协议 
AF_IMPLINK: IMP链接层 
  • 1.
  • 2.
  • 3.
  • 4.

套接字类型:

SOCK_STREAM: 流式套接字 
SOCK_DGRAM: 数据报套接字 
SOCK_RAW: 原始套接字 
SOCK_SEQPACKET: 定序分组套接字
  • 1.
  • 2.
  • 3.
  • 4.
SOCKET m_Socket;
m_Socket = INVALID_SOCKET;
if ((m_Socket=socket(AF_INET, SOCK_DGRAM,0))== INVALID_SOCKET)
{ 
AfxMessageBox("创建套接字失败!"); 
} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

#p#(4) 服务端绑定端口。

端口号范围:1024到65535,低于1024的端口对应着因特网上的一些常见服务。

struct sockaddr { u_short sa_family;   // 地址族地址族 address family address family char sa_data[14];

// 14字节的协议地址 up to 14 bytes of direct address }; typedef struct sockaddr SOCKADDR; typedef struct sockaddr *PSOCKADDR; typedef struct sockaddr FAR *LPSOCKADDR;

struct sockaddr_in { short sin_family;// 地址族 u_short sin_port;// 端口号 struct in_addr sin_addr; // IP地址 char sin_zero[8];// 填充0 }; typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr_in *PSOCKADDR_IN; typedef struct sockaddr_in FAR *LPSOCKADDR_IN;

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

字节顺序转换函数:

htons():"Host to Network Short" htonl():"Host to Network long" ntohs():"Network to Host Short" ntohl():"Network to Host Long"

SOCKADDR_IN m_saAddr; u_short m_nPort = 20049;// 端口号 ZeroMemory(&m_saAddr, sizeof(m_saAddr)); m_saAddr.sin_family  = AF_INET; m_saAddr.sin_port= htons(m_nPort); // 如果此值为0,系统将随机选择一个未被使用的端口号 m_saAddr.sin_addr.s_addr = INADDR_ANY;  // 填入本机IP地址 if (bind(m_Socket, (LPSOCKADDR) &m_saAddr, sizeof(m_saAddr)) == SOCKET_ERROR) { AfxMessageBox("绑定端口失败!"); }

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

#p#(5) 注册网络事件。

网络事件定义:

FD_READ: 网络数据包到达 
FD_WRITE: 发送网络数据 
FD_OOB: OOB数据到达 
FD_ACCEPT: 收到连接请求 
FD_CONNECT: 已建立连接 
FD_CLOSE: 断开连接 
FD_QOS: 服务质量(QoS)发生变化 
FD_GROUP_QOS: 保留事件 
FD_ROUTING_INTERFACE_CHANGE: 指定地址的路由接口发生变化 
FD_ADDRESS_LIST_CHANGE: 本地地址变化
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
#define WM_NETWORK_EVENT WM_USER + 102
if (WSAAsyncSelect(m_Socket, m_hWnd, WM_NETWORK_EVENT, FD_READ) == SOCKET_ERROR)
{
AfxMessageBox("注册网络事件失败!");
} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

(6) 处理网络事件。

afx_msg LRESULT OnNetworkEvent(WPARAM wParam, LPARAM lParam); ON_MESSAGE(WM_NETWORK_EVEN, OnNetworkEvent)

LRESULT OnNetworkEvent(WPARAM wParam, LPARAM lParam) { switch (WSAGETSELECTEVENT(lParam)) { case FD_READ: // 接收数据 break; } return 0L; }

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

#p#(7) 读取数据。

BOOL Read(void) { int nBytesRead; int nBufferLength; int nEnd; int nSpaceRemaining; char chIncomingDataBuffer[4096]; SOCKADDR_IN m_saFromAddr; int nLenght = sizeof(m_saFromAddr); ZeroMemory(&m_saFromAddr, sizeof(SOCKADDR_IN)); nEnd = 0; nBufferLength = sizeof(chIncomingDataBuffer); nSpaceRemaining = sizeof(chIncomingDataBuffer); nSpaceRemaining -= nEnd;

nBytesRead = recvfrom(m_Socket, (LPSTR) (chIncomingDataBuffer + nEnd), nSpaceRemaining, 0, (LPSOCKADDR) &m_saFromAddr, &nLenght); nEnd += nBytesRead; if (nBytesRead == SOCKET_ERROR) { AfxMessageBox("读取数据出错!") return FALSE; } // IP地址:inet_ntoa(m_saFromAddr.sin_addr); // 端口号:ntohs(m_saFromAddr.sin_port); chIncomingDataBuffer[nEnd] = '\0'; if (lstrlen(chIncomingDataBuffer) != 0) { AfxMessageBox(chIncomingDataBuffer); } return TRUE; }

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

#p# (8) 发送数据。

BOOL Send(CString sIP, u_short nPort, CString sSendData)
{
DWORDdwIP;
SOCKADDR_IN saAddr;
if (m_Socket == INVALID_SOCKET)
{
AfxMessageBox("套接字不可用!");
return FALSE;
}
if ((dwIP = inet_addr(sIP)) == INADDR_NONE)
{
AfxMessageBox("无法获取目标IP!");
return FALSE;
}
saAddr.sin_family  = AF_INET;
saAddr.sin_port= htons(nPort);
saAddr.sin_addr.s_addr = dwIP;
if (sendto(m_Socket, sSendData, sSendData.GetLength(), 0, (LPSOCKADDR) &saAddr, sizeof(saAddr)) == SOCKET_ERROR)
{
AfxMessageBox("发送数据失败!");
return FALSE;
}
return TRUE;
} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

(9) 关闭套接字。

if (m_Socket != INVALID_SOCKET)
{
closesocket(m_Socket);
}
m_Socket = INVALID_SOCKET;
WSACleanup(); 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

具体WinSock API实现UDP协议的过程已经全部讲完。UDP协议真正的优势在于它具有TCP协议所不具备的功能,如:广播、多播和穿透NAT等等。

责任编辑:佟健 来源: 网界网
相关推荐

2010-06-29 12:42:05

UDP协议Java

2010-07-09 11:15:55

Visual C# U

2010-07-13 09:29:37

socketUDP协议

2010-07-06 15:16:34

UDP协议

2013-08-01 10:01:02

网络协议TCP协议UDP协议

2010-07-08 14:35:32

UDP协议

2010-07-08 12:42:34

UDP协议

2010-06-28 15:45:07

UDP协议

2010-07-05 16:17:18

UDP协议

2020-01-03 07:57:39

UDPTCP网络协议

2010-07-12 21:14:09

UDP协议

2014-06-13 13:47:31

UDP

2010-07-07 11:17:01

UDP协议应用

2010-07-01 16:55:03

UDP协议

2010-07-09 09:29:00

UDP协议

2010-06-12 15:30:57

UDP协议

2010-07-06 15:10:05

UDP协议

2010-07-09 11:12:09

UDP协议

2010-07-12 15:40:24

2010-06-21 17:51:50

UDP协议
点赞
收藏

51CTO技术栈公众号