这是我参与11月更文挑战的第十三天,活动详情查看:2021最后一次更文挑战
什么是UPD传输协议
UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,OSI 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。
目的和要求
1. 了解网络协议的基本概念;
2. 掌握UDP基础通信模型的服务器与客户端的通讯过程;
3. 掌握SOCKET的创建;
4. 了解gets和scanf的区别。
内容和步骤
服务器端:
1、包含网络头文件网络库
#include <stdio.h>
//1、包含网络头文件网络库
# include <WinSock2.h>
# pragma comment(lib, "Ws2_32.lib")
#pragma warning(disable:4996)
2、打开网络库
//2、打开网络库
int iret = WSAStartup(wVersionRequested, &wsaDATA);
if (iret != 0)
{
//有错
switch (iret)
{
case WSASYSNOTREADY:
printf("解决方案:重启。。。");
break;
case WSAVERNOTSUPPORTED:
printf("解决方案:更新网络库");
break;
case WSAEINPROGRESS:
printf("解决方案:重启。。。");
break;
case WSAEPROCLIM:
printf("解决方案:网络连接达到上限或阻塞,关闭不必要软件");
break;
case WSAEFAULT:
printf("解决方案:程序有误");
break;
}
getchar();
return 0;
}
3、校验版本
if (2 != HIBYTE(wsaDATA.wVersion) || 2 != LOBYTE(wsaDATA.wVersion))
{
printf("版本有问题!");
WSACleanup();//关闭网络库
return 0;
}
4、创建SOCKET
socketServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (INVALID_SOCKET == socketServer)
{
//清理网络库,不关闭句柄
WSACleanup();
return 0;
}
5、绑定地址与端口
struct sockaddr_in si;
si.sin_family = AF_INET;//这里要和创建SOCKET句柄的参数1类型一样
si.sin_port = htons(9527);//用htons宏将整型转为端口号的无符号整型
si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if (bind(socketServer, (struct sockaddr*)&si, sizeof(si)) == SOCKET_ERROR)
{
int err = WSAGetLastError();//取错误码
printf("服务器bind失败错误码为:%d\n", err);
closesocket(socketServer);//释放
WSACleanup();//清理网络库
}
7.与客户端收发消息
while (1)
{
//收
struct sockaddr sa;
int iSaLen = sizeof(sa);
char strRecvBuff[548] = { 0 };
char csendbuff[1500] = { 0 };
if (recvfrom(socketServer, strRecvBuff, 548, 0, &sa, &iSaLen) == SOCKET_ERROR)
{
int err = WSAGetLastError();//取错误码
printf("服务器recvfrom失败错误码为:%d\n", err);
continue;
}
printf("服务器recvfrom消息是:%s\n", strRecvBuff);
//发
//if (sendto(socketServer, "This is a message from server~!", sizeof("This is a message from server~!"), 0, &sa, sizeof(sa)) == SOCKET_ERROR)
//{
// int err = WSAGetLastError();//取错误码
// printf("服务器sendto失败错误码为:%d\n", err);
// continue;
//}
scanf("%s", csendbuff);
if (send(socketServer, csendbuff, sizeof(csendbuff), 0) == SOCKET_ERROR)
{
int err = WSAGetLastError();//取错误码
printf("server send失败错误码为:%d\n", err);
//不用关闭socket
//根据实际情况处理
}
}
客户端:
1、包含网络头文件网络库
#include <stdio.h>
//1、包含网络头文件网络库
# include <WinSock2.h>
# pragma comment(lib, "Ws2_32.lib")
#pragma warning(disable:4996)
2、打开网络库
//2、打开网络库
int iret = WSAStartup(wVersionRequested, &wsaDATA);
if (iret != 0)
{
//有错
switch (iret)
{
case WSASYSNOTREADY:
printf("解决方案:重启。。。");
break;
case WSAVERNOTSUPPORTED:
printf("解决方案:更新网络库");
break;
case WSAEINPROGRESS:
printf("解决方案:重启。。。");
break;
case WSAEPROCLIM:
printf("解决方案:网络连接达到上限或阻塞,关闭不必要软件");
break;
case WSAEFAULT:
printf("解决方案:程序有误");
break;
}
getchar();
return 0;
}
3、校验版本
if (2 != HIBYTE(wsaDATA.wVersion) || 2 != LOBYTE(wsaDATA.wVersion))
{
printf("版本有问题!");
WSACleanup();//关闭网络库
return 0;
}
4、创建SOCKET
socketClient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (INVALID_SOCKET == socketClient)
{
//清理网络库,不关闭句柄
WSACleanup();
return 0;
}
//服务器地址与端口
struct sockaddr_in si;
si.sin_family = AF_INET;//这里要和创建SOCKET句柄的参数1类型一样
si.sin_port = htons(9527);//用htons宏将整型转为端口号的无符号整型
si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
//客户端不用绑定操作
/*
if(bind(socketServer,(struct sockaddr*)&si,sizeof(si))==SOCKET_ERROR)
{
int err = WSAGetLastError();//取错误码
printf("服务器bind失败错误码为:%d\n",err);
closesocket(socketServer);//释放
WSACleanup();//清理网络库
}
*/
5、与服务器端收发消息
while (1)
{
//发
char strSendBuff[548] = { 0 };
scanf("%s", strSendBuff);
if (sendto(socketClient, strSendBuff, sizeof(strSendBuff), 0, (const struct sockaddr*)&si, sizeof(si)) == SOCKET_ERROR)
{
int err = WSAGetLastError();//取错误码
printf("客户端sendto失败错误码为:%d\n", err);
continue;
}
//收
struct sockaddr sa;
int iSaLen = sizeof(sa);
char strRecvBuff[548] = { 0 };
if (recvfrom(socketClient, strRecvBuff, 548, 0, &sa, &iSaLen) == SOCKET_ERROR)
{
int err = WSAGetLastError();//取错误码
printf("客户端recvfrom失败错误码为:%d\n", err);
continue;
}
printf("客户端recvfrom消息是:%s\n", strRecvBuff);
}
记住,在使用完网络库之后一定要关闭。
closesocket(socketClient);//与4、创建SOCKET对应,如果有创建客户端SOCKET句柄,也要关闭
//关闭网络库
WSACleanup();
system("pause");
return 0;
UDP基础通信模型与TCP基础通信模型有什么区别?
1、UDP简单,速度更快,更高效,(无连接,无验证,头信息少协议代码判断就少);
2、数据不可靠,(无验证);
3、不管是数据报,还是字节流,都是在传输线路上传输的数据,对于传输线路而言是没有区别的,区别在于数据到了传输层之后的处理方式,数据报就是数据报的形式处理,字节流就以流的特点处理。
小结
如果这篇文章对你有帮助的话,记得三连凹~