DevC++ 用C语言的多线程 实现简单的客户端和服务器

知识来源一:

使用Dev-C++实现简单的客户端和服务器-CSDN博客

此先生的博客使用的是win32 SDK来创建多线程,然后鄙人对这个版本的多线程细节不明。于是又重新用C语言的线程替代win32API,以此继续学习服务器代码。

知识来源二:DevC++ 多线程创建与删除与exe文件脱离DevC++运行中发现dll文件和exe文件的关系-CSDN博客

这是C语言多线程简单样例。

然后在这两个基础上优化知识来源一的服务端代码,过程中查询函数,然后复制博客链接和截取解释,产生了知识来源三如下,作为函数忘了可以怎么开发了,就翻回去参考的,集成小文案。

知识来源三:

DevC++ socket嵌套字实现局域网客户端服务端函数详解注释-CSDN博客

优化功能说明:

客户端命令: log_out : 切断客户端在服务器的联系

消息反馈功能:客户端输入消息后,服务端发送反馈消息,说明可以服务端可以直接利用已经建立的链接传输消息,不用再另外建一新联系。

增加过程提示:函数执行过程中printf运行阶段,是当时改线程创建忘新建线程的bug加的测试点。

效果如图

零起点的顺序是,先看知识来源二的文章,玩玩里面的代码demo,键盘命令创建取消线程。然后看本节文章,对着知识点三,把本节文章的单线程服务器注释取消掉,删掉多线程部分。理解一个服务器一个客户端的联系的建立,然后再看看多线程代码,读读注释,用自己的话再说说,然后自己独立写写多线程服务器代码,写20min要是写不动了就仔细描述自己怎么写不出来的,是不会无中生有,连猜也猜不出来通信需要什么凭证,还是说是函数参数忘了默认值。然后再看看参考代码,理解自己是通过怎样的观察,在限定的时间里发现自己重复中却不能重复出新的思路。避免死磕,发现规模重复不能产生新意就回归,在现有的参考标准里的继续学习,临摹思路与代码。然后再试试能不能整活加点料,实现新功能。

完整代码如下,如果服务器代码编译的exe文件点击运行时,提示缺少libwinpthread-1.dll文件,有bug原理与解决方案,详情刚才的知识来源二:DevC++ 多线程创建与删除与exe文件脱离DevC++运行中发现dll文件和exe文件的关系-CSDN博客

服务端,有小的注释。

#include <stdio.h>
#include <winsock2.h>
#include<pthread.h>
#include<string.h>
#include<conio.h>
#pragma comment(lib,"ws2_32.lib")//这两个注释块是win32API函数写的的多线程函数,用于对照c语言多线程 //typedef struct ThreadNode
//{
//	int index;
//	HANDLE ThreadId;
//	SOCKET Client;
//	struct ThreadNode * next;
//	ThreadNode()
//	{
//		index = 0;
//		this->next = NULL;
//	}
//}hThread;typedef struct ThreadNode {int index;pthread_t* Thread;SOCKET Client;struct ThreadNode * next;ThreadNode() {index = 0;this->next = NULL;}
} hThread;hThread *clientHeadNote, *clientEndNote;
hThread * addClient() {hThread * ClientNote = new hThread();return ClientNote;
}//DWORD WINAPI ThreadClient(LPVOID param)
//{
//	if(clientEndNote == NULL)
//	{
//		printf("empty Link\n");
//		return 0;
//	}
//	char revData[255];
//	SOCKET sClient = clientEndNote->Client;
//	while(1)
//	{
//			//接收数据
//	    int ret = recv(sClient, revData, 255, 0);
//	    if(ret > 0)
//	    {
//	        revData[ret] = 0x00;
//	        printf(revData);
//	        puts(0);
//	    }
//	}
//	closesocket(sClient);
//}//每个建立链接的客户端分配一个函数,每个线程运行一个这样的函数 
void* ThreadClient(void*) {if (clientEndNote == NULL) {printf("empty Link\n");return 0;}char revData[255];SOCKET sClient = clientEndNote->Client;printf("client logged in \n");while (1) {//接收数据int ret = recv(sClient, revData, 255, 0);if (ret > 0) {revData[ret] = 0x00;printf(revData);
//			puts(0);printf("\n");
//				    新功能:加入客户端控制签退if (strcmp("log_out", revData) == 0) {char a[255];strcpy(a, "已注销\n");send(sClient, a, 255, 0);
//				反馈:向客户端sClienr发送“已注销”消息,发送长度为255个字节,0是指不阻塞。
//				printf("签退成功\n");closesocket(sClient);printf("签退成功\n");} else {char a[255];strcpy(a, "服务器已收到消息\n");send(sClient, a, 255, 0);}}}closesocket(sClient);
}int main(int argc, char* argv[]) {//初始化WSAWORD sockVersion = MAKEWORD(2, 2);WSADATA wsaData;if (WSAStartup(sockVersion, &wsaData) != 0) {return 0;}//创建套接字SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (slisten == INVALID_SOCKET) {printf("socket error !");return 0;}//绑定IP和端口sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(8888);
//	端口和客户端端口要相同,否则链接建立不上 
//		sin.sin_port = htons(8880);sin.sin_addr.S_un.S_addr = INADDR_ANY;
//	这个是any指的是不限制访问IP//	sin.sin_addr.S_un.S_addr =htonl(INADDR_ANY);
//	char loa[16] = "192.168.15.189";
//	sin.sin_addr.S_un.S_addr = inet_addr(loa);//	把sin强制类型转换为sockadd,sin原来是sockaddr_in类型
//	初始化slisten,加载上面代码设置的属性。 if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) {printf("bind error !");}//开始监听if (listen(slisten, 5) == SOCKET_ERROR) {printf("listen error !");return 0;}//	以上可以认为是建立服务器联系的固定格式//下面注释部分是单线程的服务器,就是只能接受一个客户端的服务器 //循环接收数据
//	SOCKET sClient;
//	sockaddr_in remoteAddr;
//	int nAddrlen = sizeof(remoteAddr);
//	char revData[255];接受消息拉到外部,建立联系就一直接受
//	printf("等待连接...\n");
//	sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
//	if (sClient == INVALID_SOCKET) {
//		printf("accept error !");continue;
//	}
//	printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
//
//
//	while (true) {
//		//接收数据
//		int ret = recv(sClient, revData, 255, 0);ret是数据长度 sclient是数据来源 revdata是数据,255是长度上限,0是不阻塞
//		if (ret > 0) {
//			revData[ret] = 0x00;
//			printf(revData);
//			printf("\n");
//		}
//		//发送数据
//		char a[100]="服务器已收到消息\n";scanf("%s", a);
//		send(sClient, a, strlen(a), 0);
//	}
//
//	closesocket(slisten);
//	WSACleanup();
//	return 0;//这里是多线程服务器,接受多个客户端,可以对比单线程看看多了什么,哪些函数的位置调整了sockaddr_in remoteAddr;int nAddrlen = sizeof(remoteAddr);while (true) {printf("等待连接...\n");SOCKET sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);if (sClient == INVALID_SOCKET) {printf("accept error !");continue;}printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));if (clientHeadNote == NULL) {clientHeadNote = addClient();
//			printf("node creat\n");clientEndNote = clientHeadNote;}
//		clientEndNote->Client = sClient;
//		clientEndNote->ThreadId = CreateThread(NULL, 0, ThreadClient, NULL, 0, NULL);//	必须要先创建给end节点,然后再创建线程,因为线程的参数通过全局变量传入,而不是通过线程生成函数传入 
//	原来线程参数除了 pthread_create()还能通过全局变量传参数hThread* clientnode = (hThread*)malloc(sizeof(hThread));clientnode->Client = sClient;clientnode->next = NULL;clientHeadNote->next = clientnode;clientEndNote = clientnode;printf("endnode is created\n");clientnode->Thread = (pthread_t*)malloc(sizeof(pthread_t));clientnode->index = pthread_create(clientnode->Thread, NULL, ThreadClient, NULL);printf("线程创建成功\n");}printf("server is closing\n"); hThread * p;while (clientHeadNote) { //释放占用的内存空间
//	    	CloseHandle(clientHeadNote->ThreadId);p = clientHeadNote;clientHeadNote = clientHeadNote->next;delete p;}closesocket(slisten);WSACleanup();return 0;
}

客户端,但是注释更零散

#include <WINSOCK2.H>
#include <STDIO.H>
#include<pthread.h>
#pragma  comment(lib,"ws2_32.lib")//格式和服务端一样
int main(int argc, char* argv[]) {WORD sockVersion = MAKEWORD(2, 2);WSADATA data;if (WSAStartup(sockVersion, &data) != 0) {return 0;}SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (sclient == INVALID_SOCKET) {printf("无效的 socket !");return 0;}sockaddr_in serAddr;serAddr.sin_family = AF_INET;//表示使用IPv4地址协议
//    https://blog.csdn.net/u012736362/article/details/130392547serAddr.sin_port = htons(8888);//    puts("请输入对方的IP地址");char loa[16] = "127.0.0.1";
//	就是当服务器的电脑的IP , win建+r 输入cmd,打开命令行,输入再直接 ipconfig/all可查看IP。 // IP是读取目标机器的IP,由于一台电脑当服务器和客户端,127.0.0.1是自回路,自己发送给自己serAddr.sin_addr.S_un.S_addr = inet_addr(loa);
//    IP赋值//链接发消息if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR) {//主动连接服务器printf("连接错误 !");closesocket(sclient);return 0;}puts("连接成功!!");puts("你现在可以向服务器发送信息:");while (1) {char sendData[100];
//		gets(sendData);scanf("%s",sendData);send(sclient, sendData, strlen(sendData), 0);
//		send(sclient, sendData, 255, 0);
//		匹配长度 255个字节//		Sleep(1500);
//		if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR) {
//			//主动连接服务器
//			printf("连接错误 !");
//			closesocket(sclient);
//			return 0;
//		}
//		puts("连接成功!!");
//		puts("你现在可以向服务器发送信息:");char recData[255];int ret = recv(sclient, recData, 255, 0);
//		接收服务端消息 if (ret > 0) {recData[ret] = 0x00;printf(recData);}}
//    char recData[255];
//    int ret = recv(sclient, recData, 255, 0);
//    if(ret > 0)
//    {
//        recData[ret] = 0x00;
//        printf(recData);
//    }closesocket(sclient);WSACleanup();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317117.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从初创公司的角度来看微服务

在开展微服务的过程中&#xff0c;了解要考虑哪些因素可能是非常有挑战性的事情。没有可以直接使用的金科玉律。每个过程都是不同的&#xff0c;因为每个组织面临的都是不同的环境。在本文中&#xff0c;我将从初创公司的角度分享我们学习到的经验和面临的挑战&#xff0c;以及…

MySQL 集群方案介绍

mysql集群方案这里介绍2种&#xff0c;PXC 和 Replication。大型互联网程序用户群体庞大&#xff0c;所以架构设计单节点数据库已经无法满足需求。大家也深有体会&#xff0c;有一万人在学校网站查成绩或是选课的时候网站时常是访问不了或者相应特别特别慢。这种情况就凸显出来…

ML.NET案例详解:在.NET下使用机器学习API实现化学分子式数据格式的判定

半年前写过一篇类似的文章&#xff0c;题目是&#xff1a;《在.NET中使用机器学习API&#xff08;ML.NET&#xff09;实现化学分子式数据格式的判定》&#xff0c;在该文中&#xff0c;我介绍了化学分子式数据格式的基本知识&#xff0c;同时给出了一个案例&#xff0c;展示了如…

数据结构之线段树合并——永无乡,Lomsat gelral,Tree Rotations,Tree Rotations Escape Through Leaf

文章目录[HNOI2012]永无乡Lomsat gelral「POI2011 R2 Day2」旋转树木 Tree RotationsEscape Through Leaf线段树合并与 fhq-treap合并很类似&#xff0c;也是将两个不同根的线段树暴力合并至于时间复杂度&#xff0c;线段树合并一次是可以达到O(n)O(n)O(n)的&#xff0c;但是大…

吉特仓储管理系统--开源2018年源码

应该说今天过完&#xff0c;这个年就算真正意义上的过完了&#xff0c;没有想到的是又是在出差的路上写这样的文章。废话也不多说&#xff0c;写这篇文章主要的目的是想将去年吉特仓储管理系统开发的一个版本源代码开放出来&#xff0c;供各位开发者阅读使用。github 源代码地址…

自定义Visual Studio.net Extensions 开发符合ABP vnext框架代码生成插件[附源码]

介绍我很早之前一直在做mvc5 scaffolder的开发功能做的已经非常完善,使用代码对mvc5的项目开发效率确实能成倍的提高,就算是刚进团队的新成员也能很快上手,如果你感兴趣 可以参考 http://neozhu.github.io/MVC5-Scaffolder/#/ https://github.com/neozhu/MVC5-Scaffolder但是m…

洛谷P1650:田忌赛马(贪心)

解析 其实并不简单的一道题。 是刘汝佳老师的例题&#xff0c;搜到之后按照讲的策略写了一发。 &#xff08;由于这个策略并不完全正确&#xff0c;就不展开讲了&#xff09; 好啊&#xff01; 可是感觉讲的策略特别对&#xff0c;为什么呢&#xff1f; 原因在于&#xff0…

EFCore Lazy Loading + Inheritance = 干净的数据表 (二)

前言本篇是上一篇EFCore Lazy Loading Inheritance 干净的数据表 &#xff08;一&#xff09; 【献给处女座的DB First程序猿】 前菜 的续篇。这一篇才是真的为处女座的DB First程序猿准备的正餐。继续上一篇的话题&#xff0c;我们希望用EFCore&#xff0c;且继续使用与逻辑…

我们为什么要搞长沙.NET技术社区?

某种意义上讲&#xff0c;长沙和中国大部分内地城市一样&#xff0c;都是互联网时代的灯下黑。没有真正意义上的互联网公司&#xff0c;例如最近发布的中国互联网企业一百强中没有一家湖南或者长沙的公司就是明证。然而长沙并非没有互联网人&#xff0c;在麓谷几十万计的IT 从业…

在ASP.NET Core中使用EPPlus导入出Excel文件

这篇文章说明了如何使用EPPlus在ASP.NET Core中导入和导出.xls/.xlsx文件&#xff08;Excel&#xff09;。在考虑使用.NET处理excel时&#xff0c;我们总是寻找第三方库或组件。使用Open Office Xml格式&#xff08;xlsx&#xff09;读取和写入Excel 2007/2010文件的最流行的.n…

月旦评 之 DevOps招贤令2019 - 没有人比我们更懂DevOps

公元164-182年间&#xff0c;汝南平舆的许氏兄弟于每月初一品评人物&#xff0c;褒贬时政&#xff0c;被称为“月旦评”。所谓“子治世之能臣&#xff0c;乱世之奸雄也”这句许邵评价曹操的话也是来自于“月旦评”&#xff1b;时间一下子来到了2019年&#xff0c;DevOps招贤令再…

HDU - 2204 Eddy‘s爱好(尚未完全解决)

HDU - 2204 Eddy’s爱好 题意&#xff1a; 给你一个正整数N&#xff0c;确定在1到N之间有多少个可以表示成M^K&#xff08;K>1)的数 题解&#xff1a; 参考题解&#xff1a; 我们先举例找找规律 1~10以内2的次方有多少个&#xff1f;有121,224,329,一共三个&#xff0c;…

EF Core中避免贫血模型的三种行之有效的方法(翻译)

[Paul Hiles: 3 ways to avoid an anemic domain model in EF Core &#xff1a;https://www.devtrends.co.uk/blog/3-ways-to-avoid-an-anemic-domain-model-in-ef-core]1.引言在使用ORM中&#xff08;比如Entity Framework&#xff09;贫血领域模型十分常见 。本篇文章将先探…

Saving Beans HDU - 3037(卢卡斯定理)

Saving Beans HDU - 3037&#xff08;卢卡斯定理&#xff09; 题意&#xff1a; 他们想知道有多少种方法可以在n树中保存不超过m个bean&#xff08;它们是相同的&#xff09;。 现在他们求助于你&#xff0c;你应该给他们答案。 结果可能非常巨大; 你应该输出模p的结果&…

我们为什么要搞长沙.NET技术社区(三)

我们为什么要搞长沙.NET技术社区&#xff08;三&#xff09; 小饭局搞事情先从饭局开始是中华民族的优良传统。昨天晚餐时间&#xff0c;长沙 .net 技术社区的主要发起人员进行了一番小聚&#xff0c;同时也作为一个非正式会议&#xff0c;对社区发展进行了探讨。从介绍自己对于…

【招聘(北京)】北森测评招聘 .NET 架构师、高级工程师

工作职责公司核心产品的迭代需求分析设计开发。公司核心产品的线上维护和性能调优。对初中级技术人员培养和质量把关。编写软件设计和技术文档。任职资格为人正直、诚信、责任心强&#xff0c;能承受较大工作压力。强烈的目标导向意识&#xff0c;逻辑思维清晰&#xff0c;执行…

网络流模型与技巧总结

文章目录前言常见基本模型最大匹配、最小点覆盖和最大独立集构造最小点覆盖最大点权匹配最小路径覆盖不可重覆盖可重覆盖最大权闭合子图建图技巧利用拆点进行限流利用断边表示决策利用虚点表示组合关系链状模型用链表示时间轴用链表示偏序关系形式的选取限制通过拆点描述先后顺…

卢卡斯定理 Lucas

参考文章 详细定义内容看这个参考文章 结论&#xff1a; 模板&#xff1a; Lucas函数&#xff1a; long long Lucas(long long n,long long m){if(m0) return 1;return Lucas(n/p,m/p)*C(n%p,m%p)%p; }组合数函数&#xff1a; 此处求逆元的用的bp-2 long long C(long long…

VS 2019 要来了,是时候了解一下 C# 8.0 新功能

近日&#xff0c;微软发布了 Visual Studio 2019 的发布日期&#xff0c;2019 年 4 月 2 日 Visual Studio 2019 将正式和大家见面&#xff0c;同时微软还将提供发布现场实时直播。除了 Visual Studio 2019 自身之外&#xff0c;VS 2019 的发布还牵动着很多 C# 开发者的心。虽然…

[蓝桥杯2020国赛]游园安排

题目&#xff1a; 题解&#xff1a; 本质就是求最长上升子序列&#xff0c;只不过这里是字符串版本的&#xff0c;我们都知道有n^2的LIS&#xff0c;但其实还有O(nlogn)版本的&#xff0c;详细看这里&#xff0c;套上就行 另外我发现这里竟然有蓝桥杯全套的编程题离谱&#xf…