📄 chatwinsock.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 + -