windows下的网络编程2(多线程服务器)

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;
}


测试

测试

发布了46 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42718004/article/details/86425028
今日推荐