一、服务器部分代码 头文件:server.h源文件:server.cpp
- #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*/
2、客户端代码 头文件:client.h
- #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;
- }
源文件:client.cpp
- #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*/
- #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简易网络服务器、客户端实现
最新推荐文章于 2021-08-12 10:11:48 发布