聊天室的VC代码分析

//ChatRoom 
//VC code 
//
//
#include "stdafx.h"
#include "resource.h"
#include <VECTOR>
#include <algorithm>
#include <WINSOCK2.H>
#include <ASSERT.H>

#define BUFFER_SIZE 4096
#define SERVER_MESSAGE WM_USER+100
#define CLIENT_MESSAGE WM_USER+101

// Global Variables:

SOCKET g_ListenSocket;				//Listen socket (for server)
std::vector<SOCKET>  g_DataSockets;	//All data sockets with clients (for server)
SOCKET g_ClientSocket;				//Client data socket (for client)
BOOL g_bActive;						//A tag of active socket (for both server and client)
std::string g_ChatWords;
BOOL g_bClient;						//TRUE as a client, FALSE as a server



BOOL ServerInit(HWND hWnd,UINT port);
BOOL ClientInit(HWND hWnd,UINT port,const char* serverIP);
int OnClientMessage(HWND hWnd, WPARAM wParam, LPARAM lParam);
int OnServerMessage(HWND hWnd, WPARAM wParam, LPARAM lParam);
void SendMessageToPeer(HWND hWnd);
void Send(SOCKET sock, const char* buffer, int length);
void RefreshScreen(HWND hWnd);
void ExitChat(HWND hWnd);
void GetErrorReason();

// Foward declarations of functions included in this code module:
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	// Perform application initialization:
	g_bActive=FALSE;
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_CHAT_DIALOG), NULL, (DLGPROC)WndProc);
	return 0;
}



//
//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//  PURPOSE:  Processes messages for the main window.
//  WM_COMMAND	- process the application menu
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HWND subWnd;
	char buffer[BUFFER_SIZE];
	UINT port;
	char serverIP[16];
	switch (message)
	{
	case WM_INITDIALOG:
		{
			WSADATA wsaData;
			if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
			{
				MessageBox(hWnd,"Socket Stack Error!","Error",IDOK);
				return -1;
			}
		}
		return TRUE;
	case WM_COMMAND:
		{
			switch(LOWORD(wParam))
			{
			case IDOK:
			case IDCANCEL:
				EndDialog(hWnd,LOWORD(wParam));
				break;
			case IDC_CONNECT:
				{
					subWnd=GetDlgItem(hWnd,IDC_LISTEN_PORT_C);
					GetWindowText(subWnd,buffer, BUFFER_SIZE);
					port= UINT(atoi(buffer));
					subWnd=GetDlgItem(hWnd,IDC_SERVERIP);
					GetWindowText(subWnd,buffer,BUFFER_SIZE);
					strncpy(serverIP,buffer,16);
					ClientInit(hWnd,port,serverIP);
					//g_ChatWords="";
				}
				break;

			case IDC_LISTEN:

				{
					subWnd=GetDlgItem(hWnd,IDC_LISTEN_PORT_S);
					GetWindowText(subWnd,buffer, BUFFER_SIZE);
					port= UINT(atoi(buffer));
					ServerInit(hWnd,port);
					//g_ChatWords="";

				}

				break;

			case IDC_INPUTTEXT:
				{
				if(HIWORD(wParam)==EN_UPDATE)
					{
						SendMessageToPeer(hWnd);

					}

				}

			default:

				break;

			}

		}

		break;

	case SERVER_MESSAGE:

		{

			OnServerMessage(hWnd,wParam, lParam);

		}

		break;

	case CLIENT_MESSAGE:

		{

			OnClientMessage(hWnd, wParam, lParam);

		}

		break;

	}

	return 0;

}



BOOL ServerInit(HWND hWnd,UINT port)

{

	sockaddr_in addr;

	char buffer[BUFFER_SIZE];

	ExitChat(hWnd);

	g_bClient=FALSE;

	

	//create a tcp/stream based socket

	g_ListenSocket = socket(AF_INET, SOCK_STREAM,0);

	assert(g_ListenSocket != INVALID_SOCKET);



	//set the socket as async selection tag, the related message is SERVER_MESSAGE

	//the async events contain: accept, read, write, close

	WSAAsyncSelect(g_ListenSocket, hWnd, SERVER_MESSAGE, FD_ACCEPT|FD_READ|FD_WRITE|FD_CLOSE);



	addr.sin_family = AF_INET;  //IP layer takes IP router protocol

	addr.sin_addr.S_un.S_addr = INADDR_ANY;	

	addr.sin_port = htons(port);//port from short of host to short of network



	//binding listening socket

	if(bind(g_ListenSocket, (sockaddr*)&addr, sizeof(sockaddr)) == SOCKET_ERROR)

	{

		sprintf(buffer,"Port %d has been taken. Change another port./r/n",port);

		g_ChatWords+=buffer;

		RefreshScreen(hWnd);

		MessageBox(hWnd,"Binding Error","Warnning",IDOK);

		return FALSE;

	}

	

	//listening

	if(listen(g_ListenSocket, 5) == SOCKET_ERROR)

	{

		strcpy(buffer,"Listen error./r/n");

		g_ChatWords+=buffer;

		RefreshScreen(hWnd);

		MessageBox(hWnd,"Listen Error.","Warnning",IDOK);

		return FALSE;

	}



	g_ChatWords+="Server is listening.../r/n";

	RefreshScreen(hWnd);

	g_bActive=TRUE;

	return TRUE;

}



BOOL ClientInit(HWND hWnd,UINT port,const char* serverIP)

{

	sockaddr_in addr;

	ExitChat(hWnd);

	g_bClient=TRUE;

	if(inet_addr(serverIP)==INADDR_NONE)

	{

		MessageBox(hWnd,"Invalid IP Address!","Warnning",IDOK);

		return FALSE;

	}



	//create tcp/stream data socket

	g_ClientSocket = socket(AF_INET, SOCK_STREAM,0);

	assert(g_ClientSocket != INVALID_SOCKET);



	//set the socket as async selection tag, the related message is CLIENT_MESSAGE

	//the async events contain: read, write, close, connect

	WSAAsyncSelect(g_ClientSocket,hWnd,CLIENT_MESSAGE,FD_READ|FD_WRITE|FD_CLOSE|FD_CONNECT);



	//set the server address and port

	addr.sin_family = AF_INET;

	addr.sin_addr.S_un.S_addr = inet_addr(serverIP);

	addr.sin_port = htons(port);   //short from host to network format

	

	//connect to server

	connect(g_ClientSocket, (sockaddr*)&addr, sizeof(addr));



	g_ChatWords+="Connecting.../r/n";

	RefreshScreen(hWnd);

	return TRUE;

}



int OnClientMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)

{

	char buffer[BUFFER_SIZE+1];

	int retCode;

	sockaddr_in name;

	int namelen=sizeof(sockaddr_in);



	if(WSAGETSELECTERROR(lParam))

	{

		closesocket(g_ClientSocket);

		strcpy(buffer,"Server has no response./r/n");

		g_ChatWords+=buffer;

		RefreshScreen(hWnd);

		g_bActive=FALSE;

		return 0;

	}



	switch(WSAGETSELECTEVENT(lParam))

	{

		case FD_CONNECT:

			getpeername(g_ClientSocket,(sockaddr*)&name,&namelen);

			sprintf(buffer,"Successfully connected to %s:%d./r/n",inet_ntoa(name.sin_addr),ntohs(name.sin_port));

			g_ChatWords+=buffer;

			RefreshScreen(hWnd);

			g_bActive=TRUE;

			break;

		case FD_READ:

			retCode=recv(g_ClientSocket,buffer,BUFFER_SIZE,0);

			if(retCode!=SOCKET_ERROR)

			{

				buffer[retCode]=NULL;

				g_ChatWords+=buffer;

			}

			else

				GetErrorReason();

			RefreshScreen(hWnd);

			break;

		case FD_WRITE:

			break;

		case FD_CLOSE:

			closesocket(g_ClientSocket);

			strcpy(buffer,"Server close session.Successfully log out./r/n");

			g_ChatWords+=buffer;

			RefreshScreen(hWnd);

			g_bActive=FALSE;

			break;

	}

	return 0;

}



//Server消息相应函数

int OnServerMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)

{

	SOCKET socket;

	int i,retCode,namelen;

	char buffer[BUFFER_SIZE+1];

	std::vector<SOCKET>::iterator ite;

	sockaddr_in name;

	namelen=sizeof(name);



	if(WSAGETSELECTERROR(lParam))

	{

		getpeername((SOCKET)wParam,(sockaddr*)&name,&namelen);

		closesocket((SOCKET)wParam);

		//erase the client socket from client socks list

		ite=std::find(g_DataSockets.begin(), g_DataSockets.end(),(SOCKET)wParam);

		assert(ite!=g_DataSockets.end());

		g_DataSockets.erase(ite);

		//refresh screen

		sprintf(buffer, "Client %s:%d lost contact with us./r/n", inet_ntoa(name.sin_addr),ntohs(name.sin_port));

		for(i=0; i<g_DataSockets.size(); i++)

			Send(g_DataSockets[i],buffer,strlen(buffer));

		g_ChatWords+=buffer;

		RefreshScreen(hWnd);

		return 0;

	}



	switch(WSAGETSELECTEVENT(lParam))

	{

		case FD_ACCEPT:

			//accept the client request

			socket= accept(g_ListenSocket,NULL,NULL);

			//in fact we can get the peer when calling accept, here we use getpeername instead

			getpeername(socket,(sockaddr*)&name,&namelen);

			//send a message of logining to other clients

			sprintf(buffer,"A guest joins us.(%s:%d)/r/n",inet_ntoa(name.sin_addr),ntohs(name.sin_port));

			g_ChatWords+=buffer;

			for(i=0;i<g_DataSockets.size();i++)

				Send(g_DataSockets[i],buffer,strlen(buffer));

			//send a welcome message to current client

			sprintf(buffer, "Welcome !(You ID is: %s:%d.)/r/n",inet_ntoa(name.sin_addr),ntohs(name.sin_port));

			//send(socket,buffer,strlen(buffer),0);

			Send(socket,buffer,strlen(buffer));

			//refresh srceen text

			RefreshScreen(hWnd);

			//push the client socket down to the client sockets list

			g_DataSockets.push_back(socket);

			break;

		case FD_READ:

			{

				//get the client message, the client socket ID is wParam

				retCode=recv((SOCKET)wParam,buffer,BUFFER_SIZE,0);

				buffer[retCode]=NULL;

				//send the received message to other clients

				for(i=0;i<g_DataSockets.size();i++)

				{

					if(wParam!=g_DataSockets[i])

						Send(g_DataSockets[i],buffer,strlen(buffer));

				}

				g_ChatWords+=buffer;

				//refresh screen

				RefreshScreen(hWnd);

			}

			break;

		case FD_WRITE:

			return 0;

		case FD_CLOSE: //Client gracefully close the socket

			//close the client socket who has left, the client socket ID is wParam

			getpeername((SOCKET)wParam,(sockaddr*)&name,&namelen);

			closesocket((SOCKET)wParam);

			//erase the client socket from client socks list

			ite=std::find(g_DataSockets.begin(), g_DataSockets.end(),(SOCKET)wParam);

			assert(ite!=g_DataSockets.end());

			g_DataSockets.erase(ite);

			//refresh screen

			sprintf(buffer, "Client %s:%d left./r/n", inet_ntoa(name.sin_addr),ntohs(name.sin_port));

			for(i=0; i<g_DataSockets.size(); i++)

				Send(g_DataSockets[i],buffer,strlen(buffer));

			g_ChatWords+=buffer;

			RefreshScreen(hWnd);

			break;

	}

	return 0;

}



//scroll the chat words

void RefreshScreen(HWND hWnd)

{

	HWND subWnd;

	std::string::size_type pos;

	int n;

	subWnd=GetDlgItem(hWnd,IDC_SHOWTEXT);

	SetWindowText(subWnd, g_ChatWords.c_str());

	n=0;

	pos=0;

	while((pos=g_ChatWords.find('/n',pos))!=std::string::npos)

	{

		pos++;

		n++;

	}

	SendMessage(subWnd, EM_LINESCROLL, 0, n);

}



//send message to peer

void SendMessageToPeer(HWND hWnd)

{

	HWND subwnd;

	char buffer[BUFFER_SIZE];

	int i;

	static int oldNumOfChars=0;



	subwnd=GetDlgItem(hWnd,IDC_INPUTTEXT);

	GetWindowText(subwnd,buffer,BUFFER_SIZE-2);

	if(oldNumOfChars!=strlen(buffer))

	{

		oldNumOfChars=strlen(buffer);

		return;

	}

	//empty content of input edit box

	SetWindowText(subwnd,"");

	oldNumOfChars=0;

	if(!g_bActive)

	{

		g_ChatWords+=buffer;

		g_ChatWords.erase(g_ChatWords.size(),1);

		g_ChatWords+="(Hint: you are isolated now.)/r/n";

		RefreshScreen(hWnd);

		return;

	}

	strcat(buffer,"/r/n");

	g_ChatWords+=buffer;

	RefreshScreen(hWnd);

	if(g_bClient)

	{

		Send(g_ClientSocket, buffer, strlen(buffer));

	}

	else

	{

		for(i=0;i<g_DataSockets.size();i++)

			Send(g_DataSockets[i],buffer,strlen(buffer));

	}

}



void Send(SOCKET sock, const char* buffer, int length)

{

	int ret,i;

	i=0;

	while(length>0)

	{

		ret=send(sock,&(buffer[i]),length,0);

		if(ret==0)

			break;

		else if(ret == SOCKET_ERROR)

		{

			g_ChatWords+="Error sending./r/n";

			break;

		}

		length-=ret;

		i+=ret;

	}

}



void ExitChat(HWND hWnd)

{

	int i;

	char buffer[BUFFER_SIZE];

	if(g_bActive)

	{

		if(g_bClient)

		{

			closesocket(g_ClientSocket);

			strcpy(buffer,"Successfully log out./r/n");

			g_ChatWords+=buffer;

			RefreshScreen(hWnd);

		}

		else

		{

			strcpy(buffer,"I will leave. Pls clients log out ASAP./r/n");

			for(i=0; i<g_DataSockets.size(); i++)

			{

				Send(g_DataSockets[i],buffer,strlen(buffer));

				closesocket(g_DataSockets[i]);

			}

			g_DataSockets.clear();

			

			closesocket(g_ListenSocket);

			strcpy(buffer,"Successfully close server./r/n");

			g_ChatWords+=buffer;

			RefreshScreen(hWnd);

		}

	}

	g_bActive=FALSE;

}



void GetErrorReason()

{

	LPVOID lpMsgBuf;

	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,

		NULL,WSAGetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,0,NULL);

	g_ChatWords+=(char *)lpMsgBuf;

	LocalFree( lpMsgBuf );

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值