?? server1view.cpp
字號:
// server1View.cpp : implementation of the CServer1View class
//
/*********************************************************************
//作者:趙明
//Email地址是:贊比亞番木瓜@hotmail.com;番木瓜_贊比亞@sina.com
//EMAIL:zmpapaya@hotmail.com;papaya_zm@sina.com
主頁:http://h2osky.126.com
*********************************************************************/
#include "stdafx.h"
#include "server1.h"
//#include "OnlineList.h"
#include "server1Doc.h"
#include "CntrItem.h"
#include "server1View.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CServer1View
IMPLEMENT_DYNCREATE(CServer1View, CRichEditView)
BEGIN_MESSAGE_MAP(CServer1View, CRichEditView)
//{{AFX_MSG_MAP(CServer1View)
ON_WM_DESTROY()
ON_COMMAND(ID_STAR, OnServerStart)
ON_COMMAND(ID_ADD, addfile)
ON_MESSAGE(WM_AGE1, addmessage)
ON_COMMAND(IDC_SEND, OnSend)
ON_MESSAGE(WM_KSEND,OnKSend)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CServer1View construction/destruction
LRESULT CServer1View::OnKSend(WPARAM wParam,LPARAM lParam)
{
OnSend();
return 0;
}
//此函數對應于聊天子窗口中的“發送”按鈕。
void CServer1View::OnSend()
{
//發消息
CMainFrame* pWnd=(CMainFrame*)AfxGetMainWnd();
CEdit* pEdit=(CEdit*)pWnd->m_sendbar.GetDlgItem(IDC_EDIT1);
CString temp;
pEdit->GetWindowText(temp);
if(temp.IsEmpty())
{
MessageBox("不能發送空信息!!!","警告");
pEdit->SetFocus();
return;
}
if(!m_chat)
{
MessageBox("沒有客戶聯入!!!","警告");
pEdit->SetFocus();
return;
}
temp="服務端: "+temp;
temp=temp+"\n";
Message((LPCTSTR)temp,RGB(255,0,0));
chatsocket->Send(temp.GetBuffer(0),255);
temp.ReleaseBuffer();
pWnd->m_sendbar.GetDlgItem(IDC_EDIT1)->SetFocus();
pEdit->SetWindowText("");
}
CServer1View::CServer1View()
: m_chat(FALSE)
, m_bStarted(FALSE)
, count(0)
{
// TODO: add construction code here
//zmfile全局變量(是一個結構體數組)是由頭文件server1.h引入這里的。
strcpy(zmfile[0].name,"none");
}
//顯示信息
LRESULT CServer1View::addmessage(WPARAM wParam, LPARAM lParam)
{
// MessageBox("aaa");
LPCTSTR pStr = (LPCTSTR)wParam;
Message(pStr,RGB(0,0,0));
return 1;
}
CServer1View::~CServer1View()
{
}
BOOL CServer1View::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CRichEditView::PreCreateWindow(cs);
}
//CRichEditView::OnInitialUpdate Called by the framework after the view is first attached to the document, but before the view is initially displayed.
void CServer1View::OnInitialUpdate()
{
CRichEditView::OnInitialUpdate();
//add begin
cfm.cbSize=sizeof(cfm);
cfm.bCharSet=GB2312_CHARSET;
cfm.crTextColor=RGB(0,0,0);//黑色
cfm.dwMask=CFM_CHARSET | CFM_COLOR ;
cfm.dwEffects=0;
//CRichEditView::GetRichEditCtrl Call this function to retrieve the CRichEditCtrl object associated with the CRichEditView object.
//此函數的原型是:CRichEditCtrl& GetRichEditCtrl( ) const; 我對此函數比較熟悉,在微軟的WordPad程序中經常用到此函數。
//CRichEditCtrl::SetDefaultCharFormat Sets the character formatting attributes for new text in this CRichEditCtrl object.
GetRichEditCtrl().SetDefaultCharFormat(cfm);
//add end
SetMargins(CRect(720, 720, 720, 720));
}
void CServer1View::OnDestroy()
{
// Deactivate the item on destruction; this is important
// when a splitter view is being used.
CRichEditView::OnDestroy();
COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
if (pActiveItem != NULL && pActiveItem->GetActiveView() == this)
{
pActiveItem->Deactivate();
ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
}
}
/////////////////////////////////////////////////////////////////////////////
// CServer1View diagnostics
#ifdef _DEBUG
void CServer1View::AssertValid() const
{
CRichEditView::AssertValid();
}
void CServer1View::Dump(CDumpContext& dc) const
{
CRichEditView::Dump(dc);
}
CServer1Doc* CServer1View::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CServer1Doc)));
return (CServer1Doc*)m_pDocument;
}
#endif //_DEBUG
//用此函數,在RichEdit控件中的文本的最后位置,插入指定顏色的一個字符串。
void CServer1View::Message(LPCTSTR lpszMessage,COLORREF clr)
{
//在窗口中顯示聊天信息
cfm.cbSize=sizeof(cfm);
cfm.crTextColor=clr;
cfm.dwMask=CFM_COLOR;
CString strTemp = lpszMessage;
int len = GetWindowTextLength();
//因為在上面的一句代碼中,已經將len的值設定為整個文本串的長度,所以,下面的這一句代碼的
//作用就是:將當前位置設定到RichEdit控件中的整個文本串的最后。
GetRichEditCtrl().SetSel(len,len);
//這一句的作用是:設置以后新添加的文本的顏色。
GetRichEditCtrl().SetSelectionCharFormat(cfm);
//替換選中的文本,但是由于并沒有文本被選中,所以,這一句代碼的作用其實就是:
//在當前位置插入一個串。
GetRichEditCtrl().ReplaceSel(strTemp);
}
BOOL CServer1View::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_RETURN)
{
if(GetFocus()->GetDlgCtrlID()==IDC_SEND ||GetFocus()->GetDlgCtrlID()==IDC_EDIT1)
{
// AfxGetMainWnd()->SendMessageToDescendants(WM_KSEND);
AfxMessageBox("down");
return TRUE;
}
}
return CRichEditView::PreTranslateMessage(pMsg);
}
//加文件到服務器中
int CServer1View::addfile()
{
//If your application is an OLE server, call this function to retrieve a pointer to the active main window of the application instead of directly referring to the m_pMainWnd member of the application object.
//If your application is not an OLE server, then calling this function is equivalent to directly referring to the m_pMainWnd member of your application object.
//m_wndOnline是CMainFrame類的成員。
//超過8個,就是9個了。
if(((CMainFrame*)::AfxGetMainWnd())->m_wndOnline.m_ListCtrl->GetItemCount()>8)
{
AfxMessageBox("同時最多只支持9個文件");
return 0;
}
CFileDialog cfiledlg(TRUE,NULL,NULL);
if(cfiledlg.DoModal()==IDCANCEL)//IDOK
return 0;
//fnamepath是CServer1View類的數據成員。
fnamepath=cfiledlg.GetPathName();
CFile myFile;
//在CFile::CFile 的解釋頁中找到下面的解釋:
//CFile::modeRead Opens the file for reading only.
//CFile::typeBinary Sets binary mode (used in derived classes only).有什么用???
//CFile::shareDenyNone Opens the file without denying other processes read or write access to the file. Create fails if the file has been opened in compatibility mode by any other process.
myFile.Open(fnamepath, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone);
//CFile::GetLength Obtains the current logical length of the file in bytes, not the amount.
//保存文件長度到zmfile數組的第count個元素中。
zmfile[count].length=myFile.GetLength();//文件的logical length跟amount有什么不同?
myFile.Close();
//這個for循環是用來搜索List控件,看看用戶這一次選擇要打開的文件,是否已經在List中存在了。
//如果已經存在了,就提前退出for循環。
for(int j=0;j<((CMainFrame*)::AfxGetMainWnd())->m_wndOnline.m_ListCtrl->GetItemCount();j++)
{
if(nameph[j]==fnamepath)
break;
}
//條件成立,就說明是提前退出上面的for循環的。
if((j+1)<=((CMainFrame*)::AfxGetMainWnd())->m_wndOnline.m_ListCtrl->GetItemCount())
{
AfxMessageBox("文件同名,不可加入!");
return 0;
}
if(zmfile[count].length<=0)
{
AfxMessageBox("文件大小為零,不可加入!");
return 0;
}
//如果服務器還沒啟動,則
if(!m_bStarted)
{
::MessageBox(NULL,"服務器還沒啟動,請先啟動服務器,然后再添加文件!","",0);
return 0;
}
//保存文件名到zmfile數組的第count個元素中。
strcpy(zmfile[count].name,cfiledlg.GetFileName());
//向主窗口發送WM_ADDLIST自定義消息,這樣,會導致CMainFrame::OnAddMember消息處理函數被調用。
AfxGetMainWnd()->SendMessage(WM_ADDLIST, (LPARAM)&zmfile[count],1);
CString aaa;
aaa.Format("加入文件 %s",zmfile[count].name);
aaa+='\n';
//在RichEdit控件中的文本的末尾,插入黑色的字符串aaa。
Message(aaa,RGB(0,0,0));
//下面的這句代碼,是用來初始化數組中下一個可用元素,文件名設置為“none”,路徑設置為
//上一個數組元素的文件的路徑,對,就應該這么設計。
strcpy(zmfile[count+1].name,"none");
//這個二維數組nameph是用來存儲加到List控件中的文件的全路徑用的。
//Attention:此數組的下標用的是count,而并不是count+1,這跟上一句代碼是不同的!
strcpy(nameph[count],fnamepath);
//對,因為剛剛添加了一個新的元素,所以數組元素的下標要增加一個值。
count++;
return 1;
}
void CServer1View::OnServerStart()
{
BOOL bReturn=0;
//如果服務器尚沒被啟動,則
if(!m_bStarted)
{
//啟動服務器
listensocket=new mysocket(this);
//CAsyncSocket::Create Call the Create member function after constructing a socket object to create the Windows socket and attach it.
//Return Value Nonzero if the function is successful; otherwise 0, and a specific error code can be retrieved by calling GetLastError.
//第一個參數:A well-known port to be used with the socket, or 0 if you want Windows Sockets to select a port.
bReturn=listensocket->Create(8888);//這個端口是用來接受來自客戶端的聊天請求用的。
if(bReturn==0)
::MessageBox(NULL,"執行 listensocket->Create(8888); 出錯","",0);
//CAsyncSocket::Listen Call this member function to listen for incoming connection requests.
//Return Value Nonzero if the function is successful; otherwise 0, and a specific error code can be retrieved by calling GetLastError.
bReturn=listensocket->Listen();
if(bReturn==0)
::MessageBox(NULL,"執行 listensocket->Listen(); 出錯","",0);
CMainFrame* pWnd=(CMainFrame*)AfxGetMainWnd();
CServer1App* pApp=(CServer1App*)AfxGetApp();
DWORD dwthread;
sockaddr_in local;
//socket1是一個局部變量。需要注意的是:雖然此變量是一個局部變量,但是,此變量所指向的
//新創建的socket卻并不是一個局部的對象,除非你調用closesocket函數關閉它,否則它會
//一直存在,直至進程結束。
//經過考證,發現SOCKET原來就是UINT_PTR數據類型,這是一個無符號指針類型。
// SOCKET socket1;
int rc=0;
local.sin_family=AF_INET;
//作者所設置的端口是1028,結果,我發現出錯,所以,我決定,改成3962試試看。成功了!
local.sin_port=htons(3962);
//IP地址設置成INADDR_ANY,表示:要讓系統自動獲取本機的IP地址。
local.sin_addr.S_un.S_addr=INADDR_ANY;
//調用WinSock API函數,創建了一個流式的socket,就保存在上數5行代碼處定義的局部變量中。
//If no error occurs, socket function returns a descriptor referencing the new socket. Otherwise, a value of INVALID_SOCKET is returned, and a specific error code can be retrieved by calling WSAGetLastError.
//不過,我感到奇怪的是,為什么不接著使用mysocket類,卻改用WinSock API函數呢?
//答:上面的mysocket類是用來聊天用的,是異步的;而下面的socket是用來傳送文件用的,是同步的socket;
m_sListening=socket(AF_INET,SOCK_STREAM,0);
if(m_sListening==INVALID_SOCKET)
::MessageBox(NULL,"執行 socket(AF_INET,SOCK_STREAM,0); 出錯","",0);
//執行到下面一句出錯了,返回的是錯誤信息,為什么出錯呢?
//答:因為發生了端口沖突。我把端口號改成3962就不出錯了。
//調用WinSock API函數,The bind function associates a local address with a socket.
//If no error occurs, bind returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be retrieved by calling WSAGetLastError.
rc=bind(m_sListening,(LPSOCKADDR)&local,sizeof(local));
//如果綁定IP地址和端口出錯,則
// if(!(rc==SOCKET_ERROR))//測試代碼
if(rc==SOCKET_ERROR)
{
int iErrorCode;
char str1[100];
CString aaa;
aaa="Bind錯誤\n";
iErrorCode=WSAGetLastError();//WSAENETDOWN
/*
// MessageId: WSAEADDRINUSE
//
// MessageText:
//
// Only one usage of each socket address (protocol/network address/port) is normally permitted.
//
#define WSAEADDRINUSE 10048L
*/
sprintf(str1,"bind函數返回的錯誤代碼是:%d",iErrorCode);
::MessageBox(NULL,str1,"",0);
//因為用來顯示出錯信息的View窗口是MainFrame窗口的子窗口,所以,就用了這么一個名字(xxxDescendants)
AfxGetMainWnd()->SendMessageToDescendants(WM_AGE1,(LPARAM)aaa.GetBuffer(0),1);
aaa.ReleaseBuffer();
return;//added by yjk
}
HANDLE hThread;
//The CreateThread function creates a thread to execute within the virtual address space of the calling process.
//線程函數是:listenthread;傳給線程函數的參數是:m_sListening;
//最后的一個參數是:[out] Pointer to a variable that receives the thread identifier.
//dwthread是本函數內定義的局部變量。
//啟動一個新線程,其參數m_sListening就是監聽socket。
hThread=::CreateThread(NULL,0,listenthread,(LPVOID)m_sListening,0,&dwthread);
// Check the return value for success.
if (hThread == NULL)
{
char szMsg[80];
wsprintf( szMsg, "CreateThread failed." );
::MessageBox( NULL, szMsg, "OnServerStart()", MB_OK );
}
else
{
CloseHandle( hThread );
CString aaa;
aaa="服務器啟動!\n";
Message(aaa.GetBuffer(0),RGB(0,0,0));
aaa.ReleaseBuffer();
CString strT;
strT="月影傳書,當前IP為"+pApp->m_strIp+" 開放端口號為3962";
pApp->m_pMainWnd->SetWindowText(strT);
m_bStarted=TRUE;
}
}
else
{
CString aaa;
aaa="服務器在以前已經被啟動了,無需再啟動了!\n";
Message(aaa.GetBuffer(0),RGB(0,0,0));
aaa.ReleaseBuffer();
}
}
/////////////////////////////////////////////////////////////////////////////
// CServer1View message handlers
//接受用戶
void CServer1View::accept()
{
chatsocket=new mysocket(this);
listensocket->Accept(*chatsocket);
m_chat=TRUE;
}
void CServer1View::recevied()
{
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -