当前位置: 首页 > news >正文

网络编程 udp/ip协议 c/s模型

目录

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;
}

相关文章:

  • 【数据结构】C语言实现链表(单链表部分)
  • JAVA练习8
  • 聊聊最适合程序员的画图工具
  • JAVA数据结构篇--12理解LinkedHashSetTreeSet
  • DR_CAN基尔霍夫电路题解法【自留用】
  • 21级数据结构考前模拟题
  • 剑指offer----C语言版----第六天
  • Qt音视频开发08-ffmpeg内核优化(极速打开/超时回调/实时响应)
  • 网络安全一哥的奇安信发布了全球高级可持续威胁年度报告 值得学习
  • 13---SpringBoot整合JWT,实现登录和拦截
  • 4366. 上课睡觉
  • vue后台系统管理项目-echarts柱状图实现订单统计
  • 2022年博客之星排行榜 日榜 2023-01-01 博客之星总榜
  • 一名普通Java程序员的2022的总结和2023的展望
  • 【寒假每日一题】洛谷 P1079 [NOIP2012 提高组] Vigenère 密码
  • 5、React组件事件详解
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • Git初体验
  • MySQL主从复制读写分离及奇怪的问题
  • SSH 免密登录
  • WinRAR存在严重的安全漏洞影响5亿用户
  • yii2中session跨域名的问题
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 工程优化暨babel升级小记
  • 目录与文件属性:编写ls
  • 漂亮刷新控件-iOS
  • 前端之React实战:创建跨平台的项目架构
  • 前嗅ForeSpider中数据浏览界面介绍
  • 思维导图—你不知道的JavaScript中卷
  • 06-01 点餐小程序前台界面搭建
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • 正则表达式-基础知识Review
  • # Maven错误Error executing Maven
  • (1) caustics\
  • (1)(1.11) SiK Radio v2(一)
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (16)Reactor的测试——响应式Spring的道法术器
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (附程序)AD采集中的10种经典软件滤波程序优缺点分析
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (十一)c52学习之旅-动态数码管
  • (算法)求1到1亿间的质数或素数
  • (转载)虚函数剖析
  • .net core 6 redis操作类
  • .NET Framework与.NET Framework SDK有什么不同?
  • .php结尾的域名,【php】php正则截取url中域名后的内容
  • @private @protected @public
  • [bzoj1006]: [HNOI2008]神奇的国度(最大势算法)
  • [C# WPF] DataGrid选中行或选中单元格的背景和字体颜色修改
  • [C#小技巧]如何捕捉上升沿和下降沿
  • [C++]priority_queue的介绍及模拟实现
  • [HackMyVM]靶场 Wild
  • [HDU] 1054 Strategic Game 入门树形DP
  • [HeMIM]Cl,[AeMIM]Br,[CeEIM]Cl,([HO-PECH-MIM]Cl,[HOOC-PECH-MIM]Cl改性酚醛树脂