Windows的网络编程-之三-面向无连接的协议

1      面向无连接的协议

先用socket( )或WSASocket()建立套接字,再把新创建的套接字和网络接口bind( )。和面向连接的套接字不同的是,我们不必调用listen( )和accept( ),直接发送或接收数据:

1.1     接收端

intrecvfrom(  SOCKET s,  char* buf, int len,  int flags,

structsockaddr* from,  int* fromlen  );

intWSARecvFrom(  SOCKET s,  LPWSABUF lpBuffers,  DWORD dwBufferCount,

LPDWORDlpNumberOfBytesRecvd,  LPDWORD lpFlags,

structsockaddr* lpFrom,  LPINT lpFromlen,

LPWSAOVERLAPPEDlpOverlapped,

LPWSAOVERLAPPED_COMPLETION_ROUTINElpCompletionRoutine

);

1.2     发送端

intsendto(  SOCKET s,  const char* buf,  int len, int flags,

conststruct sockaddr* to,  int tolen  );

intWSASendTo(  SOCKET s,  LPWSABUF lpBuffers,  DWORD dwBufferCount,

LPDWORDlpNumberOfBytesSent,  DWORD dwFlags,

conststruct sockaddr* lpTo,  int iToLen,

LPWSAOVERLAPPEDlpOverlapped,

LPWSAOVERLAPPED_COMPLETION_ROUTINElpCompletionRoutine

);

1.3     面向无连接的套接字的特点

面向无连接的协议几乎都是基于消息的协议,因此面向无连接的套接字也可以称为基于消息的套接字。需要注意以下几点:

在发送端,由于面向消息的协议对数据边界有保护,所以提交给发送函数的数据如果未能完全发送,发送函数就会返回错误。

在接收端,接收函数必须提供一个足够大的缓冲空间。如果提供的缓冲不够接收整个消息,接收函数就会返回错误。发生这种情况时,缓冲区会尽力接收数据,但未收完的数据会被丢弃。当然,如果使用的协议支持部分消息,就可用MSG_PARTIAL标志来避免数据的丢失。

综上所述,对于面向无连接的套接字来说,一次发送对应一次接收,发送和接收之间具有一一对应的关系。

注意:UDP套接字并不真正和网络接口绑定在一起。而是建立一种联系,即绑定的IP接口成为发送UDP数据报的源IP地址。路由表才真正决定数据报在哪个物理接口上发送出去。如果不调用bind( ),而是先调用sendto()或WSASendTo( )进行连接,网络堆栈就会根据路由表自动选出最佳IP地址,如果之前先执行了bind( ),源IP地址就会有误。

1.4     释放套接字资源

因为面向无连接的协议没有连接,所以也不会有正式的关闭。在接收端或发送端结束收发数据时,它只是在套接字上调用closesocket( ),便释放了为套接字分配的相关资源。


重叠IO模型之OverLapped完成例程模型WSACompletionRoutineServer VS2010 基础入门 客户端与服务器端 客户端向服务器端发送数据 可接收多个客户端 #include #include #pragma comment (lib, "ws2_32.lib") #define PORT 8088 #define MSG_SIZE 1024 SOCKET g_sConnect; bool g_bConnect = false; typedef struct { WSAOVERLAPPED overLap; WSABUF wsaBuf; char chMsg[MSG_SIZE]; DWORD nRecvNum; DWORD nFlags; SOCKET sClient; }PRE_IO_OPERATION_DATA, *LP_PER_IO_OPERATION_DATA; void CALLBACK CompletionRoutine(DWORD dwError, DWORD dwTrans, LPWSAOVERLAPPED lpOverlap, DWORD nFlags); DWORD WINAPI workThread(LPVOID lp) { LP_PER_IO_OPERATION_DATA lpData; while(TRUE) { if (g_bConnect) // 有新的连接 { // 为lpData分配空间并初始化 lpData = (LP_PER_IO_OPERATION_DATA)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PRE_IO_OPERATION_DATA)); lpData->wsaBuf.len = MSG_SIZE; lpData->wsaBuf.buf = lpData->chMsg; lpData->sClient = g_sConnect; WSARecv(lpData->sClient, &lpData->wsaBuf, 1, &lpData->nRecvNum, &lpData->nFlags, &lpData->overLap, CompletionRoutine); g_bConnect = false; // 处理完毕 } SleepEx(1000, TRUE); } return 0; } // 系统在WSARecv收到信息后,自动调用此函数,并传入参数--回调函数 void CALLBACK CompletionRoutine(DWORD dwError, DWORD dwTrans, LPWSAOVERLAPPED lpOverlap, DWORD nFlags) { LP_PER_IO_OPERATION_DATA lpData = (LP_PER_IO_OPERATION_DATA)lpOverlap; if (0 != dwError) // 接收失败 { printf("Socket %d Close!\n", lpData->sClient); closesocket(lpData->sClient); HeapFree(GetProcessHeap(), 0, lpData); } else // 接收成功 { lpData->chMsg[dwTrans] = '\0'; send(lpData->sClient, lpData->chMsg, dwTrans, 0); printf("Socket:%d MSG: %s \n", lpData->sClient, lpData->chMsg); memset(&lpData->overLap, 0, sizeof(WSAOVERLAPPED)); lpData->wsaBuf.len = MSG_SIZE; lpData->wsaBuf.buf = lpData->chMsg; // 继续接收来自客户端的数据 实现 WSARecv与CompletionRoutine循环 WSARecv(lpData->sClient, &lpData->wsaBuf,1, &lpData->nRecvNum, &lpData->nFlags, &lpData->overLap, CompletionRoutine); } } int main() { WSADATA wsaData; WSAStartup(0x0202, &wsaData); SOCKET sListen; sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in addrListen; addrListen.sin_family = AF_INET; addrListen.sin_port = htons(PORT); addrListen.sin_addr.S_un.S_addr = htonl(ADDR_ANY); int nErrorCode = 0; nErrorCode = bind(sListen, (sockaddr*)&addrListen, sizeof(sockaddr)); nErrorCode = listen(sListen, 5); DWORD nThreadID; CreateThread(NULL, 0, workThread, NULL, 0, &nThreadID); sockaddr_in addrConnect; int nAddrLen = sizeof(sockaddr_in); printf("Server Started!\n"); while(TRUE) { g_sConnect= accept(sListen, (sockaddr*)&addrConnect, &nAddrLen); if (INVALID_SOCKET == g_sConnect) { return -1; } g_bConnect = true; // 连接成功 printf("Accept Client :%s -- PORT:%d\n", inet_ntoa(addrConnect.sin_addr), htons(addrConnect.sin_port)); } return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值