//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 ); }
聊天室的VC代码分析
最新推荐文章于 2023-02-08 17:35:51 发布