📄 chatcsocketdlg.cpp
字号:
// ChatCSocketDlg.cpp : implementation file
//caucy 2006.2.24
#include "stdafx.h"
#include "ChatCSocket.h"
#include "ChatCSocketDlg.h"
#include <ASSERT.H>
#include <VECTOR>
#include "CMessg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define BUFFER_SIZE 4096
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
HANDLE g_ChatWordsEvent;
//BOOL g_bExit;
ULONG WINAPI ListenThread(LPVOID p);
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CChatCSocketDlg dialog
CChatCSocketDlg::CChatCSocketDlg(CWnd* pParent /*=NULL*/)
: CDialog(CChatCSocketDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CChatCSocketDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CChatCSocketDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CChatCSocketDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CChatCSocketDlg, CDialog)
//{{AFX_MSG_MAP(CChatCSocketDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_CONNECT, OnConnect)
ON_BN_CLICKED(IDC_LISTEN, OnListen)
ON_EN_UPDATE(IDC_INPUTTEXT,SendMessageToPeer)
ON_MESSAGE(WM_CONNECTION_COMEIN, WelcomeNewClient)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CChatCSocketDlg message handlers
BOOL CChatCSocketDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
m_bActive=FALSE;
g_ChatWordsEvent= CreateEvent(NULL,TRUE,TRUE,NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
void CChatCSocketDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CChatCSocketDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CChatCSocketDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CChatCSocketDlg::OnConnect()
{
// TODO: Add your control notification handler code here
sockaddr_in addr;
CString buffer;
UINT port;
char serverIP[16];
CWnd *subWnd;
//get control input
subWnd=GetDlgItem(IDC_LISTEN_PORT_C);
subWnd->GetWindowText(buffer);
port= UINT(atoi(LPCSTR(buffer)));
subWnd=GetDlgItem(IDC_SERVERIP);
subWnd->GetWindowText(buffer);
strncpy(serverIP,LPCTSTR(buffer),16);
//end last session
ExitChat();
m_bClient=TRUE;
if(inet_addr(serverIP)==INADDR_NONE)
{
AfxMessageBox("Invalid IP Address!");
return;
}
//create tcp/stream data socket
m_ClientSocket.Create(0,SOCK_STREAM);
//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
//using archieve
m_ClientSocket.Init(this);
//connect to server
if(m_ClientSocket.Connect((sockaddr*)&addr, sizeof(addr))==FALSE)
{
GetErrorReason(GetLastError());
m_ClientSocket.Close();
RefreshScreen();
return;
}
m_ChatWords+="Successful connected.\r\n";
RefreshScreen();
m_bActive=TRUE;
}
void CChatCSocketDlg::OnListen()
{
// TODO: Add your control notification handler code here
CString buffer;
CWnd *subWnd;
//close last session
ExitChat();
//get control input
subWnd=GetDlgItem(IDC_LISTEN_PORT_S);
subWnd->GetWindowText(buffer);
m_ListenPort= UINT(atoi(LPCSTR(buffer)));
if(m_ListenPort==0)
{
m_ChatWords+="Please specify a port num.\r\n";
RefreshScreen();
return;
}
m_bClient=FALSE;
m_ListenThreadHandle= CreateThread(NULL,0,ListenThread,this,NULL,NULL);
}
//recv data
void CChatCSocketDlg::OnSocketReceive(CDataSocket *pSocket,CMessg & msg)
{
if(m_bClient)
{
assert(pSocket==&m_ClientSocket);
OnClientReceive(msg);
}
else
OnServerReceive(pSocket,msg);
}
void CChatCSocketDlg::OnSocketClose(CDataSocket *pSocket)
{
if(m_bClient)
{
assert(pSocket==&m_ClientSocket);
OnClientClose();
}
else
OnServerClose(pSocket);
}
void CChatCSocketDlg::OnReceiveData(const CString & buffer)
{
if(!m_bClient)
WaitForSingleObject(g_ChatWordsEvent,INFINITE);
m_ChatWords+=buffer;
RefreshScreen();
if(!m_bClient)
SetEvent(g_ChatWordsEvent);
}
void CChatCSocketDlg::OnClientClose()
{
GetErrorReason(WSAGetLastError());
m_ClientSocket.CloseSocket();
m_ChatWords+="Server close session.Successfully log out.\r\n";
RefreshScreen();
m_bActive=FALSE;
}
void CChatCSocketDlg::WelcomeNewClient(WPARAM w, LPARAM l)
{
int namelen,i;
CString buffer;
sockaddr_in name;
CDataSocket* pSocket;
CMessg msg;
SOCKET acceptSock;
namelen=sizeof(name);
acceptSock=SOCKET(w);
if(!m_bActive) //self end socket
{
closesocket(acceptSock);
return;
}
pSocket= new CDataSocket;
pSocket->Attach(acceptSock);
CAsyncSocket* pS=CAsyncSocket::FromHandle(acceptSock);
assert(pS==pSocket);
pSocket->Init(this);
//in fact we can get the peer when calling accept, here we use getpeername instead
pSocket->GetPeerName((sockaddr*)&name,&namelen);
//send a welcome message to current client
buffer.Format("Welcome !(You ID is: %s:%d.)\r\n",inet_ntoa(name.sin_addr),ntohs(name.sin_port));
msg.m_strText=buffer;
pSocket->SendMessage(msg);
//send a message of logining to other clients
buffer.Format("A guest joins us.(%s:%d)\r\n",inet_ntoa(name.sin_addr),ntohs(name.sin_port));
m_ChatWords+=buffer;
msg.m_strText=buffer;
for(i=0; i<m_DataSockets.GetSize(); i++)
{
m_DataSockets[i]->SendMessage(msg);
}
//refresh srceen text
RefreshScreen();
//push the client socket down to the client sockets list
m_DataSockets.Add(pSocket);
}
void CChatCSocketDlg::OnClientReceive(CMessg & msg)
{
m_ChatWords+=msg.m_strText;
RefreshScreen();
}
void CChatCSocketDlg::OnServerReceive(CDataSocket *pSocket,CMessg & msg)
{
int i;
//send the received message to other clients
for(i=0;i<m_DataSockets.GetSize();i++)
{
if(pSocket!=m_DataSockets[i])
m_DataSockets[i]->SendMessage(msg);
}
WaitForSingleObject(g_ChatWordsEvent,INFINITE);
m_ChatWords+=msg.m_strText;
//refresh screen
RefreshScreen();
SetEvent(g_ChatWordsEvent);
}
void CChatCSocketDlg::OnServerClose(CDataSocket *pSocket)
{
int i,namelen;
CString buffer;
sockaddr_in name;
CMessg msg;
namelen=sizeof(name);
//close the client socket who has left, the client socket ID is wParam
pSocket->GetPeerName((sockaddr*)&name,&namelen);
pSocket->Close();
//erase the client socket from client socks list
for(i=0; i<m_DataSockets.GetSize(); i++)
{
if(m_DataSockets[i]==pSocket)
{
m_DataSockets.RemoveAt(i);
break;
}
}
//refresh screen
buffer.Format("Client %s:%d left.\r\n", inet_ntoa(name.sin_addr),ntohs(name.sin_port));
msg.m_strText=buffer;
for(i=0; i<m_DataSockets.GetSize(); i++)
m_DataSockets[i]->SendMessage(msg);
m_ChatWords+=buffer;
RefreshScreen();
delete pSocket;
}
//scroll the chat words
void CChatCSocketDlg::RefreshScreen()
{
int n;
GetDlgItem(IDC_SHOWTEXT)->SetWindowText(m_ChatWords);
n=((CEdit *)(GetDlgItem(IDC_SHOWTEXT)))->GetLineCount();
((CEdit *)(GetDlgItem(IDC_SHOWTEXT)))->LineScroll(n);
}
//send message to peer
void CChatCSocketDlg::SendMessageToPeer()
{
if(m_bClient)
{
SendMessageToPeer_Client();
}
else
{
SendMessageToPeer_Server();
}
}
void CChatCSocketDlg::SendMessageToPeer_Server()
{
CString buffer;
CMessg msg;
int i;
static int oldNumOfChars=0;
CWnd *subwnd;
subwnd=GetDlgItem(IDC_INPUTTEXT);
subwnd->GetWindowText(buffer);
if(oldNumOfChars!=buffer.GetLength())
{
oldNumOfChars=buffer.GetLength();
return;
}
//empty content of input edit box
subwnd->SetWindowText("");
oldNumOfChars=0;
if(!m_bActive)
{
WaitForSingleObject(g_ChatWordsEvent,INFINITE);
m_ChatWords+=buffer;
m_ChatWords+="(Hint: you are isolated now.)\r\n";
RefreshScreen();
SetEvent(g_ChatWordsEvent);
return;
}
WaitForSingleObject(g_ChatWordsEvent,INFINITE);
buffer+="\r\n";
m_ChatWords+=buffer;
RefreshScreen();
SetEvent(g_ChatWordsEvent);
msg.m_strText=buffer;
for(i=0;i<m_DataSockets.GetSize();i++)
m_DataSockets[i]->SendMessage(msg);
}
void CChatCSocketDlg::SendMessageToPeer_Client()
{
CString buffer;
CMessg msg;
static int oldNumOfChars=0;
CWnd *subwnd;
subwnd=GetDlgItem(IDC_INPUTTEXT);
subwnd->GetWindowText(buffer);
if(oldNumOfChars!=buffer.GetLength())
{
oldNumOfChars=buffer.GetLength();
return;
}
//empty content of input edit box
subwnd->SetWindowText("");
oldNumOfChars=0;
if(!m_bActive)
{
m_ChatWords+=buffer;
m_ChatWords+="(Hint: you are isolated now.)\r\n";
RefreshScreen();
return;
}
buffer+="\r\n";
m_ChatWords+=buffer;
RefreshScreen();
msg.m_strText=buffer;
m_ClientSocket.SendMessage(msg);
}
void CChatCSocketDlg::ExitChat()
{
if(m_bActive)
{
if(m_bClient)
ExitChat_Client();
else
ExitChat_Server();
}
m_bActive=FALSE;
}
void CChatCSocketDlg::ExitChat_Client()
{
m_ClientSocket.CloseSocket();
m_ChatWords+="Successfully log out.\r\n";
RefreshScreen();
}
void CChatCSocketDlg::ExitChat_Server()
{
int i;
CString buffer;
CMessg messg;
CDataSocket sock;
if(m_bActive)
{
//g_bExit=TRUE;
m_bActive=FALSE;
sock.Create();
sock.Init(this);
sock.Connect(LPCSTR(CDataSocket::GetIPAddress()),m_ListenPort);
//wait for listen thread exit
WaitForSingleObject(m_ListenThreadHandle,INFINITE);
CloseHandle(m_ListenThreadHandle);
messg.m_strText="I will leave. Pls clients log out ASAP.\r\n";
for(i=0; i<m_DataSockets.GetSize(); i++)
{
m_DataSockets[i]->SendMessage(messg);
m_DataSockets[i]->CloseSocket();
delete m_DataSockets[i];
}
m_DataSockets.RemoveAll();
m_ChatWords+="Successfully close server.\r\n";
RefreshScreen();
}
}
void CChatCSocketDlg::GetErrorReason(int nErrorCode)
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,nErrorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,0,NULL);
m_ChatWords+=(char *)lpMsgBuf;
LocalFree( lpMsgBuf );
}
void CChatCSocketDlg::OnOK()
{
// TODO: Add extra validation here
ExitChat();
CDialog::OnOK();
}
ULONG WINAPI ListenThread(LPVOID p)
{
CSocket listenSocket;
BOOL bRet;
CChatCSocketDlg *pDlg=(CChatCSocketDlg *)p;
CSocket dataSocket;
SOCKET acceptSock;
//create a tcp/stream based socket
bRet=listenSocket.Create(pDlg->m_ListenPort);
if(bRet==FALSE)
{
WaitForSingleObject(g_ChatWordsEvent,INFINITE);
pDlg->m_ChatWords+="Server socket create error.\r\n";
pDlg->GetErrorReason(WSAGetLastError());
pDlg->RefreshScreen();
SetEvent(g_ChatWordsEvent);
listenSocket.Close();
return -1;
}
//listening
bRet=listenSocket.Listen(5);
if(bRet == FALSE)
{
WaitForSingleObject(g_ChatWordsEvent,INFINITE);
pDlg->m_ChatWords+="Listen error.\r\n";
pDlg->GetErrorReason(WSAGetLastError());
pDlg->RefreshScreen();
SetEvent(g_ChatWordsEvent);
listenSocket.Close();
return -1;
}
WaitForSingleObject(g_ChatWordsEvent,INFINITE);
pDlg->m_ChatWords+="Server is listening...\r\n";
pDlg->RefreshScreen();
SetEvent(g_ChatWordsEvent);
pDlg->m_bActive=TRUE;
while(pDlg->m_bActive)
{
if(listenSocket.Accept(dataSocket,NULL,NULL)==FALSE)
return -1;
WaitForSingleObject(g_ChatWordsEvent,INFINITE);
acceptSock=dataSocket.m_hSocket;
dataSocket.Detach();
//If here called SendMessage, it will be deadlock
//::SendMessage(pDlg->m_hWnd,WM_CONNECTION_COMEIN,WPARAM(acceptSock),0);
::PostMessage(pDlg->m_hWnd,WM_CONNECTION_COMEIN,WPARAM(acceptSock),0);
dataSocket.Close();
SetEvent(g_ChatWordsEvent);
}
listenSocket.Close();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -