目录
1.概念编辑
2.代码解析
1.recvfrom函数
2.sendto函数
3.内核泄露问题
整体代码
1.概念
2.代码解析
1.recvfrom函数
该函数接收数据报,并存储源地址,即得到当前服务器接收到的消息,并且存储在参数2,该函数是阻塞的,会一直死等,UDP是无差别获取客户端,是与客户端1对多的关系,函数原型
int WSAAPI recvfrom(
[in] SOCKET s,
[out] char *buf,
[in] int len,
[in] int flags,
[out] sockaddr *from,
[in, out, optional] int *fromlen
);
参数1:服务器socket
参数2:字符数组,用来存储收到的消息
参数3:想要读取的字节数
参数4:数据读取方式, 0表示默认方式
参数5:获取到对方的IP地址和端口号
参数6:参数5结构体大小
返回值:成功放回字节数,失败返回SOCKET_ERROR
##代码样例
while (1)
{
struct sockaddr siClient;
char strBuf[548] = { 0 };
int nLen = sizeof(siClient);
int num = recvfrom(socketServer, strBuf, nLen, 0, &siClient, &nLen);
if (num == SOCKET_ERROR)
{
int a = WSAGetLastError();
printf("接收出错,错误码:%d\n", a);
}
}
2.sendto函数
该函数向目标发送数据,函数原型
int WSAAPI sendto(
[in] SOCKET s,
[in] const char *buf,
[in] int len,
[in] int flags,
[in] const sockaddr *to,
[in] int tolen
);
参数1:服务器socket
参数2:要发送的字符串
参数3:发送的字符串的字节数
参数4:填0
参数5:对方IP地址和端口号
参数6:参数5的大小
返回值:成功放回字节数,失败返回SOCKET_ERROR
##代码样例
//发送
int sNum = sendto(socketServer, "hello Client", sizeof("hello Client"), 0, &siClient, sizeof(siClient));
if (sNum == SOCKET_ERROR)
{
int a = WSAGetLastError();
printf("发送出错,错误码:%d\n", a);
}
3.内核泄露问题
程序关闭是没有办法释放socket和网络库的,需要在主函数中投递一个监视函数,函数原型
主函数投递监视 SetConsoleCtrlHandler(HandlerRoutine,FALSE)
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
{
switch(dwCtrlType)
{
case CTRL_CLOSE_EVENT:
//释放socket
break;
}
return FALSE;
}
##代码样例
BOOL WINAPI ctrlhandle(DWORD dwCtrlType)
{
switch (dwCtrlType)
{
case CTRL_CLOSE_EVENT:
closesocket(socketServer);
WSACleanup();
break;
}
return FALSE;
}
int main()
{
SetConsoleCtrlHandler(ctrlhandle, TRUE);//投递监视函数
//第一步 打开网络库并校验版本
}
整体代码
服务器
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib, "ws2_32.lib")
SOCKET socketServer;
BOOL WINAPI ctrlhandle(DWORD dwCtrlType)
{
switch (dwCtrlType)
{
case CTRL_CLOSE_EVENT:
closesocket(socketServer);
WSACleanup();
break;
}
return FALSE;
}
int main()
{
SetConsoleCtrlHandler(ctrlhandle, TRUE);//投递监视函数
//第一步 打开网络库并校验版本
WORD wdVersion = MAKEWORD(2, 2);
WSADATA wdSockMsg;
if (0 != WSAStartup(wdVersion, &wdSockMsg))
{
printf("打开网络库失败\n");
return 0;
}
if (2 != HIBYTE(wdSockMsg.wVersion) || 2 != LOBYTE(wdSockMsg.wVersion))
{
printf("版本不对\n");
WSACleanup();
return 0;
}
//第二步 创建socket
socketServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (socketServer == INVALID_SOCKET)
{
int a = WSAGetLastError();
printf("socket创建失败\n");
WSACleanup();
return 0;
}
//第三步 绑定ip地址和端口号
struct sockaddr_in si;
si.sin_family = AF_INET;
si.sin_port = htons(12345);
si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if (SOCKET_ERROR == bind(socketServer, (const SOCKADDR*)&si, sizeof(si)))
{
printf("绑定失败\n");
closesocket(socketServer);
WSACleanup();
return 0;
}
//第四步 收发消息
while (1)
{
//接收
struct sockaddr siClient;
char strBuf[548] = { 0 };
int nLen = sizeof(siClient);
int num = recvfrom(socketServer, strBuf, nLen, 0, &siClient, &nLen);
if (num == SOCKET_ERROR)
{
int a = WSAGetLastError();
printf("接收出错,错误码:%d\n", a);
}
printf("%s\n",strBuf);
//发送
memset(strBuf, 0, 548);
scanf("%s", strBuf);
int sNum = sendto(socketServer, strBuf, (int)strlen(strBuf), 0, &siClient, sizeof(siClient));
if (sNum == SOCKET_ERROR)
{
int a = WSAGetLastError();
printf("发送出错,错误码:%d\n", a);
}
}
closesocket(socketServer);
WSACleanup();
return 0;
}
客户端
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WORD wdVersion = MAKEWORD(2, 2);
WSADATA wdSockMsg;
if (0 != WSAStartup(wdVersion, &wdSockMsg))
{
printf("网络库打开失败\n");
return 0;
}
if (2 != HIBYTE(wdSockMsg.wVersion) || 2 != LOBYTE(wdSockMsg.wVersion))
{
printf("版本不对\n");
return 0;
}
SOCKET socketClient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (socketClient == SOCKET_ERROR)
{
printf("创建socket失败\n");
WSACleanup();
return 0;
}
struct sockaddr_in siServer;
siServer.sin_family = AF_INET;
siServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
siServer.sin_port = htons(12345);
while (1)
{
char strbuf[548] = { 0 };
scanf("%s", strbuf);
int sNum = sendto(socketClient, strbuf, (int)strlen(strbuf), 0, (const struct sockaddr*)&siServer, sizeof(siServer));
if (sNum == SOCKET_ERROR)
{
printf("发送出错\n");
}
memset(strbuf, 0, 548);
struct sockaddr siClient;
int nLen = sizeof(siClient);
int rNum = recvfrom(socketClient, strbuf, 548, 0, &siClient, &nLen);
if (rNum == SOCKET_ERROR)
{
printf("接收出错\n");
}
printf("%s\n",strbuf);
}
return 0;
}