vc简易网络服务器、客户端实现
2015-01-08 11:56
399 查看
一、服务器部分代码 头文件: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简易网络服务器、客户端实现
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- Python 网络编程---简单的服务器与客户端实现---阻塞式编写
- Go语言服务器开发之简易TCP客户端与服务端实现方法
- 利用简易Tomcat服务器结合MysqL实现Android手机注册与登录(客户端部分)
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- linux socket实现网络聊天室(一):服务器和客户端对话
- Linux网络编程--多线程实现echo服务器与客户端“一对多”功能,是网络编程的“Hello World!”
- [EK-LM3S8962]简易版智能家居:lwIP TCP/IP协议栈在ARM开发板实现嵌入式网络服务器(上)
- [java网络编程]一个简易网络服务器的实现
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- Linux 网络编程基础 客户端/服务器的简单实现
- Linux 网络编程基础(一) ---------------客户端/服务器的简单实现
- linux网络编程--服务器客户端(TCP实现)
- 简易socket客户端和多线程服务器实现
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- linux socket实现网络聊天室(一):服务器和客户端对话
- Linux 网络编程基础(一) ---------------客户端/服务器的简单实现
- Linux 网络编程实现TCP协议下的服务器客户端通信