沈阳做网站的公司排行,备案空壳网站通知,网站投放广告怎么做,网站开发需求文档范文知识来源一#xff1a;
使用Dev-C实现简单的客户端和服务器-CSDN博客
此先生的博客使用的是win32 SDK来创建多线程#xff0c;然后鄙人对这个版本的多线程细节不明。于是又重新用C语言的线程替代win32API,以此继续学习服务器代码。
知识来源二#xff1a;DevC 多线程创建…知识来源一
使用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
#includepthread.h
#includestring.h
#includeconio.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
#includepthread.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;
}