⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chatwinsock.cpp

📁 Socket的出现
💻 CPP
字号:
// ChatWinsock.cpp : Defines the entry point for the application.
//
//caucy 2006.2.20
#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 );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -