windows多线程服务器
1、这两天利用些散碎的时间,找了找资料如何在windows下搭建一个多线程的服务器,最终算是有一个简单的东西出来
2、遇到的问题有不少,简单总结一下
①、windows创建新进程和线程的函数参数很多,一开始看还是很头晕的,不过多敲敲后面感觉会好一点,创建多进程的方法搭建服务器,我不知道程序运行的顺序到底是个怎么回事,所以后面采用多线程的方法,程序执行的过程我感觉比较明确,而且多线程带来的负担比较少
②、在连接上新的客户端后,我希望服务器端可以显示出客户端的信息(IP,端口号等等),于是很正常的想到将accept()函数的返回的套接字和相应的地址当做参数传给子线程,不顾这里遇到一个问题就是,在CreateThread()函数中,参数只能传一个,于是,这里需要自己定义一个结构体:
typedef struct MyClient
{
SOCKET client_socket;
SOCKADDR_IN client_sokaddr_in;
}MyClient;
用来作为线程的传入参数
解决了这个问题后,发现在调试的时候第一次打印的端是正确的,后面端口号都会变成最后一次的客户端的端口号,找了很久的问题,网上大多说是关于传入的参数在传给线程之前被析构了之类的,不过后来定义成static还时定义成全局变量,或者给个getchar()让main()函数暂停,似乎都无法解决问题,后面经过思考,想了个方法解决了,就是在定义子线程参数时定义成自定义数组;
MyClient my_client[128];
测试问题解决(你被析构,那我就每个线程都给一个新参数)
代码
#include <stdio.h>
#include <iostream>
#include<signal.h>
#include <process.h>
#include <tchar.h>
#include "winsock2.h"
#include <windows.h>
using namespace std;
#pragma comment(lib,"WS2_32")
const unsigned short g_port = 10086; //端口
const char *g_ip = "127.0.0.1";
typedef struct MyClient
{
SOCKET client_socket;
SOCKADDR_IN client_sokaddr_in;
}MyClient;
int InitWinSork()
{
WSADATA wsadata;
int ret = 0;
ret = WSAStartup(WINSOCK_VERSION, &wsadata);
if (ret == NO_ERROR)
{
cout << "服务器启动成功" << endl;
return 1;
}
else
{
cout << "服务器启动失败" << endl;
return -1;
}
}
void * Send_and_Recv(MyClient *my_client)
{
cout << "成功连接客户端" << endl;
MyClient *ok_client = (MyClient *)my_client;
cout << "接收到客户端数据,数据来自->客户端IP:"
<< inet_ntoa(ok_client->client_sokaddr_in.sin_addr)
<< " 客户端端口号:"
<< ok_client->client_sokaddr_in.sin_port
<< endl;
char buf[512];
int ret = 0;
int n = 0;
while (1)
{
ret = recv(ok_client->client_socket, buf, 512, 0);
if (ret == 0)
{
cout << "客户端已经关闭,客户端IP: " << ok_client->client_sokaddr_in.sin_addr.s_addr << endl;
break;
}
else if (ret > 0)
{
cout << "接收到客户端数据,数据来自->客户端IP:"
<< inet_ntoa(ok_client->client_sokaddr_in.sin_addr)
<< " 客户端端口号:"
<< ok_client->client_sokaddr_in.sin_port
<< endl
<< "数据内容: ";
}
while (n < ret)
{
cout << buf[n];
n++;
}
cout << endl;
ret = send(ok_client->client_socket, buf, ret, 0);
if (ret > 0)
{
cout << "成功回送数据到客户端" << endl;
}
else
{
//cout << "error : ret = send(ok_client->client_socket, buf, ret, 0);" << endl;
cout << "客户端已经关闭,客户端IP: " << inet_ntoa(ok_client->client_sokaddr_in.sin_addr) << endl;
break;
}
}
closesocket(ok_client->client_socket);
return NULL;
}
int main(void)
{
InitWinSork();
SOCKET s_socket;
s_socket = socket(AF_INET, SOCK_STREAM, 0);
if (s_socket == INVALID_SOCKET)
{
cout << "error : s_socket = socket(AF_INET, SOCK_STREAM, 0);" << endl;
}
SOCKADDR_IN m_saddr;
m_saddr.sin_family = AF_INET;
m_saddr.sin_port = htons(g_port);
m_saddr.sin_addr.s_addr = inet_addr(g_ip);
if (bind(s_socket, (SOCKADDR *)&m_saddr, sizeof(m_saddr)) == SOCKET_ERROR)
{
cout << "error ; bind(s_socket, (SOCKADDR *)&m_saddr, sizeof(m_saddr))" << endl;
}
listen(s_socket, 128);
cout << "服务器启动成功,等待客户端连接.......... :)" << endl;
MyClient my_client[128];
SOCKADDR_IN m_caddr;
int len_m_caddr = 0;
int i = 0;
while (1)
{
SOCKET c_socket = SOCKET_ERROR;
len_m_caddr = sizeof(m_caddr);
c_socket = accept(s_socket, (SOCKADDR *)&m_caddr, &len_m_caddr);
while (c_socket == SOCKET_ERROR)
{
cout << "error ; c_socket = accept(s_socket, (SOCKADDR *)&m_caddr, &len_m_caddr);" << endl;
c_socket = accept(s_socket, (SOCKADDR *)&m_caddr, &len_m_caddr);
}
if (c_socket == INVALID_SOCKET) //INVALID_SOCKET无效套接字
{
cout << "error ; c_socket == INVALID_SOCKET" << endl;
continue; //继续监听
}
my_client[i].client_socket = c_socket;
my_client[i].client_sokaddr_in = m_caddr;
HANDLE hThread3 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Send_and_Recv, (LPVOID)&my_client[i], 0, 0);//发送
i++;
if (hThread3 != NULL)
{
CloseHandle(hThread3);
}
}
system("pause");
return 0;
}