网络编程基础---服务器分发

前天开始研究网络编程这块,感觉理解起来还是很容易,这多亏了我看过windows核心编程这本书。

不多说了,先上代码:

#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#pragma comment(lib,"ws2_32.lib")

vector<SOCKET> clientSockets;
/*recive message thread*/
DWORD WINAPI ClientThread(LPVOID lp)
{
	SOCKET sock = (SOCKET)lp;//----------
	char szbuff[1024];
	int ret;
	while(1)
	{
		//perform a blocking recv() call
		ret = recv(sock,szbuff,1024,0);
		if(ret == 0)
			break;
		else if(ret == SOCKET_ERROR)
		{
			cout << "recv() failed " << WSAGetLastError() << endl;
			break;
		}
		szbuff[ret] = '\0';
		cout << "RECV:" << szbuff <<  " " << ret << "bytes" << endl;
	}
	return 0;
}

/*send message thread*/
DWORD WINAPI SendThread(LPVOID lp)
{
	int ret;
	string msg;
	typedef vector<SOCKET>::iterator iter;
	while(1)
	{
		cin >> msg;
		iter beg = clientSockets.begin();
		for(;beg != clientSockets.end();beg++)
		{
			ret = send(*beg,msg.c_str(),msg.length() + 1,0);
			if(ret == 0)
				break;
			else if(ret == SOCKET_ERROR)
			{
				cout << "send failed " << WSAGetLastError() << endl;
				break;
			}
		}
	}
	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	//Initialize Winsock
	WSADATA wsd;
	if(WSAStartup(MAKEWORD(2,2),&wsd) != 0)
	{
		cout << "Failled to load Winsock!" << endl;
		return 1;
	}
	//create our listening socket
	SOCKET sListen,sClient;
	sListen = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
	if(sListen == SOCKET_ERROR)
	{
		cout << "socket() failed " << WSAGetLastError() << endl;
		return 1;
	}
	//Select local interface and bind to it
	struct sockaddr_in local,client;
	int iport = 5000;
	local.sin_addr.s_addr = htonl(INADDR_ANY);
	local.sin_port = htons(iport);
	local.sin_family = AF_INET;
	if(bind(sListen,(SOCKADDR*)&local,sizeof(local)) == SOCKET_ERROR)
	{
		cout << "bind() failed " << WSAGetLastError() << endl;
		return 1;
	}
	listen(sListen,8);
	cout << "server side is in listening status!" << endl;
	//Waitfor incoming clients,Once one is detected,create thread and pass
	//the handle off to it
	int iAddrSize(0);
	//HANDLE hThread;
	//DWORD dwThreadId,dwSendThreadId;
	bool createSendRecvFlag = true;
	while(1)
	{
		iAddrSize = sizeof(client);
		sClient = accept(sListen,(SOCKADDR*)&client,&iAddrSize);
		if(sClient == INVALID_SOCKET)
		{
			cout << "accept() failed " << WSAGetLastError() << endl;
			break;
		}
		cout << "Accept client:" << inet_ntoa(client.sin_addr) << endl;
		cout << ntohs(client.sin_port) << endl;

		/*save all the client sockets*/
		clientSockets.push_back(sClient);

		DWORD dwThreadId,dwSendThreadId;
		if(createSendRecvFlag)		//create one send thread for all the clients
		{
			HANDLE hSendThread = CreateThread(NULL,0,SendThread,
				(LPVOID)&clientSockets,0,&dwSendThreadId);
			createSendRecvFlag = false;
			if(hSendThread == NULL)
			{
				cout << "CreateThread() failed " << GetLastError() << endl;
				break;
			}
			CloseHandle(hSendThread);
		}
		//create a recive thread for a client
		HANDLE hThread = CreateThread(NULL,0,ClientThread,
				(LPVOID)sClient,0,&dwThreadId);
		if(hThread == NULL)
		{
			cout << "CreateThread() failed " << GetLastError() << endl;
			break;
		}
		CloseHandle(hThread);
	}
	closesocket(sListen);
    WSACleanup();
	return 0;
}

这是服务器端代码,这里涉及到两点

1.针对于客服端发来的消息怎么处理

2.如何将消息发送给所有的客服端

我的解决办法是,用一个全局变量vector<SOCKET> clientSockets;保存每一个accept来的客服端socket,给每一个客服端socket创建一个接受消息线程,而只创建一个发送消息线程统一给所有客服端发送消息。

这其实也好理解:其一服务器发送给每个客服端的消息是相同的所以只需要一个线程,遍历每一个客服端socket即可,其二客服端发送给服务器端的消息是不同的,所以采用多线程机制,不过这样也不太好,如果客服端过多,那么服务器要管理的线程就会很多,但是如果只建立一个接受线程又会出现消息阻塞情况,有待深入研究这个问题。

下面是客服端代码:

#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <iostream>
#include <string>
using namespace std;
#pragma comment(lib,"ws2_32.lib")

/*recive message thread*/
DWORD WINAPI ClientThread(LPVOID lp)
{
	SOCKET sock = (SOCKET)lp;
	char szbuff[1024];
	int ret;
	while(1)
	{
		ret = recv(sock,szbuff,1024,0);
		if(ret == 0)
			break;
		else if(ret == SOCKET_ERROR)
		{
			cout << "recv() failed " << WSAGetLastError() << endl;
			break;
		}
		szbuff[ret] = '\0';
		cout << "recv " << szbuff << " " << ret << "bytes" << endl;
	}
	return 0;
}
/*send message thread*/
DWORD WINAPI SendThread(LPVOID lp)
{
	SOCKET sock = (SOCKET)lp;
	string msg;
	int ret;
	while(1)
	{
		cin >> msg;
		ret = send(sock,msg.c_str(),msg.length() + 1,0);
		if(ret == 0)
			break;
		else if(ret == SOCKET_ERROR)
		{
			cout << "send failed " << WSAGetLastError() << endl;
			break;
		}
	}
	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	WSADATA wsd;
	SOCKET  sClient;
	struct sockaddr_in server;
	struct hostent *host = NULL;
	//load Winsock
	if(WSAStartup(MAKEWORD(2,2),&wsd) != 0)
	{
		cout << "Failled to load Winsock!" << endl;
		return 1;
	}
	//create socket and attempt to connect to the server
	sClient = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
	if(sClient == INVALID_SOCKET)
	{
		cout << "socket failed " << WSAGetLastError() << endl;
		return 1;
	}
	string szServer;
	u_short iport;
	cout << "please input IP address: " << endl;
	cin >> szServer;
	cout << "please input port number: " << endl;
	cin >> iport;
	server.sin_addr.s_addr = inet_addr(INADDR_ANY);
	server.sin_family = AF_INET;
	server.sin_port = htons(iport);
	//if the supplied server address isn't in the form
	//"aaa.bbb.ccc.ddd" it's a host name,so try to resolve it
	if(server.sin_addr.s_addr == INADDR_NONE)
	{
		host = gethostbyname(szServer.c_str());
		if(host == NULL)
		{
			cout << "unable to resolve server: " << szServer << endl;
			return 1;
		}
		CopyMemory(&server.sin_addr,host->h_addr_list[0],host->h_length);
	}
	
	if(connect(sClient,(SOCKADDR*)&server,sizeof(server))==SOCKET_ERROR)
	{
		cout << "connect failed " << WSAGetLastError() << endl;
		return 1;
	}
	cout << "connect succeed!" << endl;
	DWORD dwThreadId,dwSendThreadId;
	HANDLE hThread = CreateThread(NULL,0,ClientThread,
			(LPVOID)sClient,0,&dwThreadId);
	HANDLE hSendThread = CreateThread(NULL,0,SendThread,
			(LPVOID)sClient,0,&dwSendThreadId);
	if(hThread == NULL)
	{
		cout << "CreateThread() failed " << GetLastError() << endl;
	}
	if(hSendThread == NULL)
	{
		cout << "CreateThread() failed " << GetLastError() << endl;
	}
	CloseHandle(hThread);
	CloseHandle(hSendThread);

	//prevent main thread exit;
	while(1)
	{

	}
	closesocket(sClient);
	WSACleanup();
	return 0;
}


客服端就简单多了,就是一个收线程,一个发线程,不过这种问题只适合CS架构。至于服务器转发P2P架构就需要服务器帮助解析客服端地址了,这个想来应该不难,稍后再做研究吧

总体来说,网络编程还是要比较深厚的编程基础的,至少对于多线程要有很好的理解,难度到不大,主要就是理解一些库函数,所以更重要的问题就是设计问题,如何让服务器端的压力最小化,最优化,这点需要长期思考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值