vc简易网络服务器、客户端实现
一、服务器部分代码 头文件:server.h
- #include <winsock2.h>
- #include <stdio.h>
- #include <windef.h>
- #ifndef TCP_SERVER_H
- #define TCP_SERVER_H
- #pragma warning(disable : 4996)
- #define MAX_CLIENT (100)
- #define LISTEN_PORT (60000)
- #define CLIENT_TIMEOUT (15 * 60 * 60) /*客户端中断15分钟则服务器自动掉线*/
- #define MAX_TCP_PACKET_SIZE (1492)/*tcp最大数据包字节数*/
- typedef struct __client_item
- {
- SOCKET client;
- sockaddr_in form;
- unsigned int id;
- DWORD dwThreadId;
- HANDLE hThread;
- }_client_item;
- typedef struct __client_list
- {
- DWORD client_cnt;
- _client_item client_item[MAX_CLIENT];
- }_client_list;
- DWORD WINAPI serve_client_thread_func( LPVOID param_ptr );
- #endif/*TCP_SERVER_H*/
源文件:server.cpp
- #include "server.h"
- #include <sys\stat.h>
- #include <time.h>
- _client_list client_list;
- CRITICAL_SECTION cs_serve_main;
- CRITICAL_SECTION cs_serve_thread;
- _client_list *get_client_list(void)
- {
- return &client_list;
- }
- void client_list_cnt_inc(void)
- {
- _client_list *client_list_ptr = get_client_list();
- client_list_ptr->client_cnt++;
- }
- void client_list_cnt_dec(void)
- {
- _client_list *client_list_ptr = get_client_list();
- client_list_ptr->client_cnt--;
- }
- unsigned int get_free_client_index(void)
- {
- int i = 0;
- unsigned int id = 0;
- _client_list *client_list_ptr = get_client_list();
- for(i = 0; i < MAX_CLIENT; i++)
- {
- id = client_list_ptr->client_item[i].id;
- if( UINT_MAX == id )
- {
- break;
- }
- }
- return i;
- }
- _client_item *get_client_item(unsigned int index)
- {
- _client_list *client_list_ptr = get_client_list();
- if( index >= MAX_CLIENT )
- {
- return NULL;
- }
- return &client_list_ptr->client_item[index];
- }
- void set_client_item(unsigned int index, _client_item *client_item_ptr)
- {
- _client_list *client_list_ptr = get_client_list();
- if( index >= MAX_CLIENT )
- {
- return;
- }
- client_list_ptr->client_item[index] = *client_item_ptr;
- }
- SOCKET g_sk_server;
- int main()
- {
- SOCKET server;
- WSADATA wsaData;
- sockaddr_in local;
- int nRet = 0;
- int sockaddr_in_sizeof = 0;
- unsigned int index = 0;
- _client_item *client_item_ptr = NULL;
- _client_item client_item = {0};
- _client_list *client_list_ptr = NULL;
- SOCKET client;
- sockaddr_in from;
- DWORD dwThreadId;
- HANDLE hThread;
- nRet = WSAStartup(0x101, &wsaData);
- if( 0 != nRet )
- {
- return 0;
- }
- // 现在我们来为sockaddr_in结构赋值。
- local.sin_family = AF_INET; // 地址族
- local.sin_addr.s_addr = INADDR_ANY; // 网际IP地址
- local.sin_port = htons(LISTEN_PORT); // 使用的端口
- // 由socket函数创建我们的SOCKET。
- server = socket(AF_INET, SOCK_STREAM, 0);
- //server = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL, 0, WSA_FLAG_OVERLAPPED);
- // 如果socket()函数失败,我们就退出。
- if( server == INVALID_SOCKET )
- {
- return 0;
- }
- // bind将我们刚创建的套接字和sockaddr_in结构联系起来。
- // 它主要使用本地地址及一个特定的端口来连接套接字。
- // 如果它返回非零值,就表示出现错误。
- nRet = bind(server, (sockaddr*)&local, sizeof(local));
- if( 0 != nRet )
- {
- return 0;
- }
- // listen命令套接字监听来自客户端的连接。
- // 第二个参数是最大连接数。
- nRet = listen(server, MAX_CLIENT);
- if( 0 != nRet )
- {
- return 0;
- }
- g_sk_server = server;
- // 我们需要一些变量来保存客户端的套接字,因此我们在此声明之。
- InitializeCriticalSection(&cs_serve_main);/*初始化临界区*/
- InitializeCriticalSection(&cs_serve_thread);/*初始化临界区*/
- client_list_ptr = get_client_list();
- memset(client_list_ptr, 0xff, sizeof(_client_list));
- memset(&client, 0, sizeof(SOCKET));
- memset(&from, 0, sizeof(sockaddr_in));
- sockaddr_in_sizeof = sizeof(sockaddr_in);
- while( TRUE )
- {
- index = get_free_client_index();
- if( index >= MAX_CLIENT )
- {/*已经达到最大连接数*/
- continue;
- }
- client_item_ptr = get_client_item(index);
- client_item_ptr->client = accept(server,
- (struct sockaddr*)&client_item_ptr->form, &sockaddr_in_sizeof);
- if( INVALID_SOCKET == client_item_ptr->client )
- {/*连接错误*/
- Sleep(500);
- continue;
- }else
- {
- printf("Connection from %s\n", inet_ntoa(client_item_ptr->form.sin_addr) );
- }
- /* 多线程开始*/
- EnterCriticalSection(&cs_serve_main);/*进入临界区*/
- hThread = CreateThread(
- NULL, // no security attributes
- 0, // use default stack size
- serve_client_thread_func, // thread function
- client_item_ptr, // argument to thread function
- CREATE_SUSPENDED, // use default creation flags
- &dwThreadId); // returns the thread identifier
- if( NULL != hThread )
- {
- client_item_ptr->hThread = hThread;
- client_item_ptr->dwThreadId = dwThreadId;
- client_item_ptr->id = index;
- }
- client_list_cnt_inc();
- LeaveCriticalSection(&cs_serve_main);/*离开临界区*/
- if( NULL != client_item_ptr->hThread )
- {
- ResumeThread(client_item_ptr->hThread);
- }
- client_item_ptr = NULL;
- /*end 多线程开始*/
- }
- //关闭套接字,并释放套接字描述符。
- closesocket(server);
- WSACleanup();
- DeleteCriticalSection(&cs_serve_thread);/*删除临界区*/
- DeleteCriticalSection(&cs_serve_main);/*删除临界区*/
- return 0;
- }
- void serve_client_thread_clear(SOCKET sock_client,
- sockaddr_in *sockaddr_client_ptr,
- UINT32 client_id,
- char *msg,
- _client_item *client_item_ptr
- )
- {
- int msg_len = strlen(msg);
- if( msg_len > 0 )
- {
- send(sock_client, msg, msg_len + 1, 0);
- }
- closesocket(sock_client);/*关闭连接*/
- client_list_cnt_dec();
- memset(client_item_ptr, 0, sizeof(_client_item));
- set_client_item(client_id, client_item_ptr);
- }
- DWORD WINAPI serve_client_thread_func(LPVOID param_ptr)
- {
- char buf[MAX_TCP_PACKET_SIZE];
- _client_item *client_item_ptr = (_client_item *)param_ptr;
- SOCKET sock_client = 0;
- sockaddr_in sockaddr_client = {0};
- unsigned int client_id = 0;
- _client_list *client_list_ptr = get_client_list();
- int recv_size = 0;
- time_t sock_free_cur_time = 0;
- time_t sock_free_kill_time = 0;
- int n_ret = 0;
- fd_set fdread;
- timeval tv;
- while( NULL == client_item_ptr->hThread );
- sock_client = client_item_ptr->client;
- sockaddr_client = client_item_ptr->form;
- client_id = client_item_ptr->id;
- sprintf(buf, "%s:%d you id=%d\n", inet_ntoa(sockaddr_client.sin_addr),
- sockaddr_client.sin_port, client_id);
- send(sock_client, buf, strlen(buf) + 1, 0);
- do
- {
- /*这部分代码在此处必须每次都执行*/
- FD_ZERO(&fdread);//初始化fd_set
- FD_SET(sock_client, &fdread);//分配套接字句柄到相应的fd_set
- tv.tv_sec = 1;//这里我们打算让select等待1s后返回,避免被锁死,也避免马上返回
- tv.tv_usec = 0;
- /*end 这部分代码在此处必须每次都执行*/
- select(0, &fdread, NULL, NULL, &tv);
- n_ret = FD_ISSET(sock_client, &fdread);
- if( 0 == n_ret )/*没有数据*/
- {
- continue;
- }
- recv_size = recv(sock_client, buf, sizeof(buf), 0);
- if( recv_size <= 0)
- {/*socket 错误,断开连接并退出*/
- /*超时,线程退出*/
- printf("client time out ip=%s:port=%d:id=%d\n",
- inet_ntoa(sockaddr_client.sin_addr), sockaddr_client.sin_port, client_id);
- EnterCriticalSection(&cs_serve_thread);/*进入临界区*/
- memset(buf, 0, sizeof(buf));
- serve_client_thread_clear(sock_client, &sockaddr_client, client_id, buf, client_item_ptr);
- LeaveCriticalSection(&cs_serve_thread);/*离开临界区*/
- ExitThread(0);/*退出线程*/
- }
- sock_free_cur_time = 0;
- if( ('q' == buf[0]) && (0 == buf[1]) )
- {/*客户端主动退出*/
- sprintf(buf, "client exit server ip=%s:port=%d:id=%d\n",
- inet_ntoa(sockaddr_client.sin_addr), sockaddr_client.sin_port, client_id);
- EnterCriticalSection(&cs_serve_thread);/*进入临界区*/
- serve_client_thread_clear(sock_client, &sockaddr_client, client_id, buf, client_item_ptr);
- LeaveCriticalSection(&cs_serve_thread);/*离开临界区*/
- ExitThread(0);/*退出线程*/
- }
- printf("ip=%s:port=%d:id=%d say:%s\n", inet_ntoa(sockaddr_client.sin_addr),
- sockaddr_client.sin_port, client_id, buf);
- }while( TRUE );
- return 0;
- }
2、客户端代码 头文件:client.h
- #include <winsock2.h>
- #include <stdio.h>
- #include <windef.h>
- #ifndef TCP_CLIENT_H
- #define TCP_CLIENT_H
- #pragma warning(disable : 4996)
- #define TCP_SERVER_ADDR "192.168.0.2"
- #define TCP_SERVER_PORT (60000)
- #define MAX_TCP_PACKET_SIZE (1492)/*tcp最大数据包字节数*/
- #endif/*end TCP_CLIENT_H*/
源文件:client.cpp
- #include "client.h"
- int main()
- {
- int nRet = 0;
- WORD wVersionRequested;//版本号
- WSADATA wsaData;
- SOCKET sock;
- SOCKADDR_IN server_addr;
- char buf[MAX_TCP_PACKET_SIZE];
- int recv_size = 0;
- wVersionRequested = MAKEWORD(1, 1);//1.1版本的套接字
- nRet = WSAStartup(wVersionRequested, &wsaData);
- if( nRet )
- {
- return nRet;
- }
- if (LOBYTE(wsaData.wVersion) != 1 ||
- HIBYTE(wsaData.wVersion) != 1)
- {
- return -1;
- }//判断高低字节是不是1,如果不是1.1的版本则退出
- sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if( INVALID_SOCKET == sock )
- {
- return -1;
- }
- server_addr.sin_addr.S_un.S_addr = inet_addr(TCP_SERVER_ADDR);
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(TCP_SERVER_PORT);
- nRet = connect(sock, (SOCKADDR*)&server_addr, sizeof(SOCKADDR) );
- if( 0 != nRet )
- {
- return nRet;
- }
- recv(sock, buf, sizeof(buf), 0);
- printf(buf);
- do
- {
- memset(buf, 0, sizeof(buf));
- printf("please write some thing:");
- gets(buf);
- send(sock, buf, strlen(buf) + 1, 0);
- if( ('q'== buf[0]) && (0 == buf[1]) )
- {
- recv_size = recv(sock, buf, sizeof(buf), 0);
- printf(buf);
- break;
- }
- }while( TRUE );
- closesocket(sock);
- WSACleanup();//必须调用这个函数清除参数
- return 0;
- }
vc简易网络服务器、客户端实现相关推荐
- python学习(九) 网络编程学习--简易网站服务器
python `网络编程`和其他语言都是一样的,服务器这块步骤为: `1. 创建套接字` `2. 绑定地址` `3. 监听该描述符的所有请求` `4. 有新的请求到了调用accept处理请求` Pyt ...
- python网络平台_python学习(九) 网络编程学习--简易网站服务器
python `网络编程`和其他语言都是一样的,服务器这块步骤为: `1. 创建套接字` `2. 绑定地址` `3. 监听该描述符的所有请求` `4. 有新的请求到了调用accept处理请求` Pyt ...
- python应用系列教程——python使用SocketServer实现网络服务器,socket实现客户端
全栈工程师开发手册 (作者:栾鹏) python教程全解 python使用SocketServer实现网络服务器 SocketServer简化了网络服务器的编写.在进行socket创建时,使用Sock ...
- c++网络编程:实现简单的聊天——基于服务器/客户端的模式
c++ socket编程 服务器/客户端 最近在学c++网路编程,写个帖子记录自己的学习过程,部分内容参考一个博主的,附上他的链接: link 实现: 客户端往服务器端发送一条数据,服务器端接收数据并 ...
- Unity网络--HLAPI(1):服务器客户端变量同步,脏标识以及定制特性SyncVar
服务器客户端变量同步 在网络游戏中,大部分事务都是在服务器内处理的,例如NPC被玩家攻击后减HP,服务器需要将变化的HP值传到各个客户端,客户端更新此HP值后,客户端才会显示减血后的NPC血量,这种同 ...
- linux tcp客户端端口号,Linux网络编程--服务器客户端(TCP实现)
Linux下的一个服务器客户端的小程序,基于TCP的实现:服务器可以同时接受多个客户的接入,通过子进程处理客户请求,下面的例子中,服务器只将客户的IP和端口以及发送的信息显示,然后原样的将客户发送的信 ...
- cefsharp 发送请求服务器_使用 WPF 版简易 SIP 服务器向 GB28181 摄像头发送直播请求...
使用 WPF 版简易 SIP 服务器向 GB28181 摄像头发送直播请求 目录 一.引言 二.项目渊源 三.软件使用及 SIP INVITE 流程 (一) 注册和心跳 (二) 直播 INVITE 四 ...
- 如何编写一个简易网络爬虫
感谢小臣投稿 本文将简述网络爬虫及其工作流程,结合个人实践,简单介绍如何使用HttpClient.HtmlParser第三方jar工具包,编写一个简易的网络爬虫. 网络爬虫简述及流程架构 网络爬虫,又 ...
- Java小程序之简易网络画板
Java小程序之简易网络画板 一.前言: Java是一门网络编程语言,强大的网络可以让数据进行传送:今天,我们就小试牛刀,看看Java是如何进行网络传输数据的: 二.项目分析: 1.功能需求: 我们前 ...
最新文章
- Unity 2021创建2D休闲点击器游戏视频教程
- 三步10分钟搞定数据库版本的降迁 (将后台数据库SQL2008R2降为SQL2005版本)
- 一维随机变量及其概率分布
- 拦截器HandlerInterceptor、ResponseBodyAdvice和@ExceptionHandler执行顺序
- 表的插入、更新、删除、合并操作_20_通过表关联删除多张表
- ORACLE ORA-02030: can only select from fixed tables/views
- string.Split(params char[])”最匹配的重载方法具有一些无效参数
- linux 查看ip_如何在 Linux 中查看可用的网络接口 | Linux 中国
- chart.js x轴显示不全_机床大讲堂第67讲——基于FANUC系统的数控铣床增加第四轴的方法...
- 1.无重复字符的最长子串
- day46-CSS3新增功能
- 用VB无窗口透明Usercontrol编写透明浮动按钮
- 爬虫是后端吗_北京市互联网后端职位招聘需求分析
- Spring-IOC本质
- Java语句详解(图解java语句概念、快速掌握java基础知识点)——Java基础系列
- AttributeError: 'list' object has no attribute 'send_keys',python+selenium 实现QQ空间网页的自动登陆。
- Gym 100781A Adjoin the Networks——树的直径
- charles——教程——转载
- 畅购商城-添加订单实现(一)
- Halcon复习专题-镜头/匹配/标定/边缘/拟合/缺陷检测/
热门文章
- Babel的安装和使用
- 用CMake编译运行在网上下载的源文件src
- 走近人脸检测:从VJ到深度学习(下)
- Caffe学习系列(18): 绘制网络模型
- 基于当前分支的某一个commit号创建分支
- Spring - Java/J2EE Application Framework 应用框架 第 18 章 使用Quartz或Timer完成时序调度工作
- 简明python教程 --C++程序员的视角(一):数值类型、字符串、运算符和控制流
- 趣味编程:从字符串中提取信息(参考答案 - 下)
- 06_Dart异常处理
- “生于忧患,死于安乐”之程序员人生