我的大作业——MFC开发的聊天工具(局域网形式,飞秋的半实现版)

///
// TCPClient.h文件

include

include

include

pragma comment(lib,”WS2_32.lib”)

class CMyApp : public CWinApp
{
public:
BOOL InitInstance();
};

class CMainDialog : public CDialog
{
public:
CMainDialog(CWnd* pParentWnd = NULL);

protected:
// 连接服务器
BOOL Connect(LPCTSTR pszRemoteAddr, u_short nPort);
// 向文本框中添加文本
void AddStringToList(LPCTSTR pszText, BOOL bRecv = TRUE);

protected:
// 状态栏子窗口控件
CStatusBarCtrl m_bar;
CListCtrl m_Ctrl;
// 用于与服务器取得连接的套节字句柄
SOCKET m_socket;

protected:
virtual BOOL OnInitDialog();
virtual void OnCancel();
// 取得或断开连接
afx_msg void OnButtonConnect();
// 发送数据
afx_msg void OnButtonSend();
// 清空编辑框
afx_msg void OnButtonClear();
afx_msg void OnClickItem(NMHDR* pNMHDR, LRESULT* pResult);
// 套节字通知事件
afx_msg long OnSocket(WPARAM wParam, LPARAM lParam);

afx_msg void OnSendFile();
afx_msg void Receivefile();
DECLARE_MESSAGE_MAP()

};


/
// TCPClient.cpp文件

include “TCPClient.h”

include “resource.h”

// 定义网络事件通知消息s

include “ZMySocket.h”

include “afxdlgs.h”

include

define WM_SOCKET WM_USER + 1

define port 8888

define IDC_LIST 101

CMyApp theApp;
int nRow;

BOOL CMyApp::InitInstance()
{
// 初始化Winsock库
WSADATA wsaData;
WORD sockVersion = MAKEWORD(2, 0);
::WSAStartup(sockVersion, &wsaData);
// 弹出主窗口对话框
CMainDialog dlg;
m_pMainWnd = &dlg;
dlg.DoModal();
// 释放Winsock库
::WSACleanup();
return FALSE;
}

CMainDialog::CMainDialog(CWnd* pParentWnd):CDialog(IDD_MAINDIALOG, pParentWnd)
{
}

BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
ON_BN_CLICKED(IDC_CONNECT, OnButtonConnect)
ON_BN_CLICKED(IDC_SEND, OnButtonSend)
ON_BN_CLICKED(IDC_CLEAR, OnButtonClear)
ON_BN_CLICKED(IDC_SendFile,OnSendFile)
ON_MESSAGE(WM_SOCKET, OnSocket)
END_MESSAGE_MAP()

BOOL CMainDialog::OnInitDialog()
{
CDialog::OnInitDialog();
// 设置图标
SetIcon(theApp.LoadIcon(IDI_MAIN), FALSE);
// 创建状态栏,设置它的属性
m_bar.Create(WS_CHILD | WS_VISIBLE | SBS_SIZEGRIP, CRect(0, 0, 0, 0), this, IDC_LIST);
m_bar.SetBkColor(RGB(0, 0, 0)); // 背景色
int arWidth[] = { 200, -1 };
m_bar.SetParts(2, arWidth); // 分栏
m_bar.SetText(“”, 1, 0); // 第一个栏的文本
m_bar.SetText(” 空闲”, 0, 0); // 第二个栏的文本
// 初始化发送按钮和发送编辑框的状态
//win32代码
m_Ctrl.Create(WS_VISIBLE, CRect(400, 8, 650, 270), this, 101);
//m_Ctrl.SetBkColor(RGB(100, 100, 100));
m_Ctrl.InsertColumn(0, “用户名”,LVCFMT_LEFT, 100);
m_Ctrl.InsertColumn(1, “IP”,LVCFMT_LEFT, 150);

m_Ctrl.SetExtendedStyle(LVS_EX_FULLROWSELECT |
    LVS_EX_GRIDLINES |
    LVS_EX_HEADERDRAGDROP |
    LVS_EX_TRACKSELECT);


LONG lStyle;
lStyle = GetWindowLong(m_Ctrl.m_hWnd, GWL_STYLE);
lStyle &= ~LVS_TYPEMASK; //清除显示方式位
lStyle |= LVS_REPORT; //设置style
SetWindowLong(m_Ctrl.m_hWnd, GWL_STYLE, lStyle);//设置style

nRow = m_Ctrl.GetItemCount();

GetDlgItem(IDC_SEND)->EnableWindow(FALSE);
GetDlgItem(IDC_TEXT)->EnableWindow(FALSE);

// 初始化连接套节字
m_socket = INVALID_SOCKET;

return TRUE;

}

void CMainDialog::OnCancel()
{
if(m_socket != INVALID_SOCKET)
::closesocket(m_socket);

CDialog::OnCancel();

}

void CMainDialog::OnButtonClear()
{
GetDlgItem(IDC_INFO)->SetWindowText(“”);
}

void CMainDialog::OnButtonConnect()
{
if(m_socket == INVALID_SOCKET) // 连接服务器
{
// 取得服务器地址
CString sAddr = “10.140.17.21”;

    // 试图连接服务器
    if(!Connect(sAddr, port))
    {
        MessageBox("连接服务器出错!");
        return;
    }
    // 设置用户界面
    GetDlgItem(IDC_CONNECT)->SetWindowText("取消");
    //m_bar.SetText(" 正在连接……", 0, 0);
}
else                // 断开服务器
{
    // 关闭套节字

    ::closesocket(m_socket);
    m_socket = INVALID_SOCKET;

    // 设置用户界面
    GetDlgItem(IDC_CONNECT)->SetWindowText("连接服务器");
    m_bar.SetText(" 空闲", 0, 0);
    //GetDlgItem(IDC_ADDR)->EnableWindow(TRUE);
    //GetDlgItem(IDC_PORT)->EnableWindow(TRUE);
    GetDlgItem(IDC_TEXT)->EnableWindow(FALSE);
    GetDlgItem(IDC_SEND)->EnableWindow(FALSE);
    m_Ctrl.DeleteAllItems();
}

}

long CMainDialog::OnSocket(WPARAM wParam, LPARAM lParam)
{
// 取得有事件发生的套节字句柄
SOCKET s = wParam;
// 查看是否出错
if(WSAGETSELECTERROR(lParam))

{
    if(m_socket != SOCKET_ERROR)
        OnButtonConnect();
    m_bar.SetText(" 连接出错!", 0, 0);
    return 0;
}

// 处理发生的事件
switch(WSAGETSELECTEVENT(lParam))
{   
case FD_CONNECT:    // 套节字正确的连接到服务器
    {
        // 设置用户界面
        GetDlgItem(IDC_CONNECT)->SetWindowText("断开连接");

        //GetDlgItem(IDC_ADDR)->EnableWindow(FALSE);
        //GetDlgItem(IDC_PORT)->EnableWindow(FALSE);
        GetDlgItem(IDC_TEXT)->EnableWindow(TRUE);
        GetDlgItem(IDC_SEND)->EnableWindow(TRUE);
        m_bar.SetText(" 已经连接到服务器", 0, 0);
    }
    break;

case FD_READ:       // 套接字接受到对方发送过来的数据包
    {
        // 从服务器接受数据
        char szText[1024] = { 0 };
        ::recv(s, szText, 1024, 0);
        // 显示给用户
        AddStringToList(CString(szText) + "\r\n");
    }
    break;

case FD_CLOSE:
    OnButtonConnect();
    break;
}

return 0;

}

void CMainDialog::OnButtonSend()
{
if(m_socket == INVALID_SOCKET)
{
return;
}

// 取得要发送的字符串
CString sText;
CString str;
for (int i = 0; i<m_Ctrl.GetItemCount(); i++)
{
    if (m_Ctrl.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED)
    {
        str.Format("%d", i);
        sText += str;
        sText += ",";
    }

}
sText += " ";
CString sText2;
GetDlgItem(IDC_TEXT)->GetWindowText(sText2);
sText += sText2;







// 添加一个“回车换行”
// 注意,添加它并不是必须的,但是如果使用本软件作为客户端调试网络协议,
// 比如SMTP、FTP等,就要添加它了。因为这些协议都要求使用“回车换行”作为一个命令的结束标记
sText += "\r\n";

// 发送数据到服务器
SOCKET_STREAM_FILE_INFO     StreamFileInfo;

memset(&StreamFileInfo, 0, sizeof(SOCKET_STREAM_FILE_INFO));
strcpy(StreamFileInfo.text,sText);
StreamFileInfo.sendflags = MESSAGE;

if (::send(m_socket, (LPSTR)&StreamFileInfo, sizeof(StreamFileInfo), 0) != -1)
{
    sText2 += "\r\n";
    AddStringToList(sText2, FALSE);
    GetDlgItem(IDC_TEXT)->SetWindowText("");
}

}

BOOL CMainDialog::Connect(LPCTSTR pszRemoteAddr, u_short nPort)
{
// 创建套节字
m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(m_socket == INVALID_SOCKET)
{
return FALSE;
}

// 设置socket为窗口通知消息类型
::WSAAsyncSelect(m_socket, m_hWnd,
    WM_SOCKET, FD_CONNECT | FD_CLOSE | FD_WRITE | FD_READ);

// 假定szAddr是IP地址
ULONG uAddr = ::inet_addr(pszRemoteAddr);
    if(uAddr == INADDR_NONE)
{
            // 不是IP地址,就认为这是主机名称
    // 从主机名取得IP地址
    hostent* pHost = ::gethostbyname(pszRemoteAddr);
    if(pHost == NULL)
    {
        ::closesocket(m_socket);
        m_socket = INVALID_SOCKET;
        return FALSE;
    }
    // 得到以网络字节顺序排列的IP地址
            uAddr = ((struct in_addr*)*(pHost->h_addr_list))->s_addr;
    }

    // 填写服务器地址信息
sockaddr_in remote;
    remote.sin_addr.S_un.S_addr = uAddr;
    remote.sin_family = AF_INET;
    remote.sin_port = htons(nPort);
    // 连接到远程机
    ::connect(m_socket, (sockaddr*)&remote, sizeof(sockaddr));

return TRUE;

}

void CMainDialog::AddStringToList(LPCTSTR pszText, BOOL bRecv)
{
CString strEdit;
GetDlgItem(IDC_INFO)->GetWindowText(strEdit);

if (bRecv)
{

    CString a = CString(pszText);

    char a1 = a[0];
    if (a1 == '1')
    {
        m_Ctrl.DeleteAllItems();

        int pos = a.Find("\r\n");
        CString cs;
        cs.Format("%d", pos);
        //strEdit += cs;
        //strEdit += a;
        bool assure = true;
        while (pos != 0)
        {
            CString str1 = a.Left(pos);
            int lenn = a.GetLength() - pos;
            a = a.Right(lenn - 1);
            int pos1 = str1.Find(":");
            CString left = str1.Left(pos1);
            int len2;
            if (assure)
                len2 = left.GetLength() - 1;
            else
                len2 = left.GetLength() - 2;
            left = left.Right(len2);
            int len = str1.GetLength() - pos1 - 1;
            CString right = str1.Right(len);
            /*
            strEdit += left;
            strEdit += "hahah";
            strEdit += right;
            strEdit += "\r\n";
            */
            m_Ctrl.InsertItem(nRow, "");
            m_Ctrl.SetItemText(nRow, 0, left);
            m_Ctrl.SetItemText(nRow, 1, right);
            //strEdit += a;
            pos = a.Find("\r\n");

            cs.Format("%d", pos);
            if (pos == 1)
                pos--;
            //strEdit += cs;
            assure = false;
        }

        /*
            CString str1 = a.Left(pos);
            int lenn = a.GetLength()-pos;
            a = a.Right(lenn);
            int pos1 = str1.Find(":");
            CString left = str1.Left(pos1);
            int len2 = left.GetLength() - 1;
            left = left.Right(len2);
            int len = str1.GetLength() - pos1 - 1;
            CString right = str1.Right(len);
            strEdit += left;
            strEdit += "hahah";
            strEdit += right;
            m_Ctrl.InsertItem(nRow, "");
            m_Ctrl.SetItemText(nRow, 0, left);
            m_Ctrl.SetItemText(nRow, 1, right);
            pos = a.Find("\r\n");
            CString cs;
            cs.Format("%d", pos);
            strEdit += cs;
            */
        /*
        CString left = a.Left(pos);
        int len2 = left.GetLength() - 1;
        left = left.Right(len2);
        int len = a.GetLength() - pos - 1;
        CString right = a.Right(len);
        strEdit += left;
        strEdit += "hahah";
        strEdit += right;

        m_Ctrl.InsertItem(nRow, "");
        m_Ctrl.SetItemText(nRow, 0, left);
        m_Ctrl.SetItemText(nRow, 1, right);
        */
    }
    else
    {
        strEdit += "【ReceiveFrom】";
        strEdit += a;
        strEdit += "\r\n";
    }


}
else
{
    strEdit += "【Send】:";
    strEdit += pszText;
}
GetDlgItem(IDC_INFO)->SetWindowText(strEdit);

}

void CMainDialog::OnSendFile()
{

CFileDialog Dlg(TRUE);
if (Dlg.DoModal() != IDOK)
    return;

CFile myFile;
if (!myFile.Open(Dlg.GetPathName(), CFile::modeRead | CFile::typeBinary))
{
    AfxMessageBox("文件不存在!", MB_OK | MB_ICONERROR);
    return;
}
/*
char name[32];
int nGethostname;

nGethostname = gethostname(name, sizeof(name));
if(nGethostname == SOCKET_ERROR)
{
return ;
}
//本地
struct hostent FAR * hostent;

hostent  = gethostbyname(name);
char * host = inet_ntoa(*((struct in_addr *)hostent->h_addr));
*/
Message  message;
::memset(&message, '\0', sizeof(message));
message.sendflags = SENDFILE;
//::strcpy((LPSTR)(LPCTSTR)message.ipaddress, host);
//::strcpy((LPSTR)(LPCTSTR)message.username,ipAddr);
/*
m_socket.Send(&message, sizeof(message), 0);

///
CMySocket fileSocket;
//{{socket 初始化
bool isFileCreate;

isFileCreate = fileSocket.Create();
if(isFileCreate == false)
{
::MessageBox(NULL, "创建 socket 失败 !", "Message Box", MB_OK);
::WSACleanup();
return;
}


//{{Bind
bool               bBind;
struct sockaddr_in serveraddr;
int                length;

serveraddr.sin_family       = AF_INET;
serveraddr.sin_port         = PORT;
serveraddr.sin_addr.s_addr  = inet_addr(host);

length = sizeof(struct sockaddr_in);

bBind = fileSocket.Bind((struct sockaddr *)&serveraddr, length);
if(bBind == false)
{
::MessageBox(NULL, "绑定 socket 失败 jksajd!", "Message Box", MB_OK);
::WSACleanup();
return;
}
fileSocket.Listen();
SOCKET sockRecv;
sockRecv = fileSocket.Accept((struct sockaddr FAR*)&serveraddr, &length);
*/

/*
CSocket sockSrvr;
sockSrvr.Create(800);

sockSrvr.Listen();
CSocket sockRecv;
sockSrvr.Accept(sockRecv);
*/
SOCKET_STREAM_FILE_INFO     StreamFileInfo;
WIN32_FIND_DATA             FindFileData;

FindClose(FindFirstFile(Dlg.GetPathName(), &FindFileData));
memset(&StreamFileInfo, 0, sizeof(SOCKET_STREAM_FILE_INFO));
strcpy(StreamFileInfo.szFileTitle, myFile.GetFileTitle());

StreamFileInfo.dwFileAttributes = FindFileData.dwFileAttributes;
StreamFileInfo.ftCreationTime = FindFileData.ftCreationTime;
StreamFileInfo.ftLastAccessTime = FindFileData.ftLastAccessTime;
StreamFileInfo.ftLastWriteTime = FindFileData.ftLastWriteTime;
StreamFileInfo.nFileSizeHigh = FindFileData.nFileSizeHigh;
StreamFileInfo.nFileSizeLow = FindFileData.nFileSizeLow;
StreamFileInfo.sendflags = SENDFILE;

//::send(sockRecv,&(char *)StreamFileInfo,sizeof(SOCKET_STREAM_FILE_INFO),0);

UINT dwRead = 0;
//while (dwRead<StreamFileInfo.nFileSizeLow)
//{
    byte* data = new byte[10240];
    UINT dw = myFile.Read(data, 10240);
    //message.fileBuffer = new byte[1024];
    for (int i = 0; i < dw; i++)
        StreamFileInfo.fileBuffer[i] = data[i];
    StreamFileInfo.dw = dw;
    send(m_socket, (LPSTR)&StreamFileInfo, sizeof(SOCKET_STREAM_FILE_INFO), 0);
    //::send(sockRecv,(char *)data, dw,0);
    dwRead += dw;
//}
myFile.Close();

//::closesocket(sockRecv);

}

void CMainDialog::Receivefile()
{
AfxMessageBox(“接收完毕!”);
AfxSocketInit(NULL);
CSocket sockClient;
sockClient.Create();
CString szIP;
if (!sockClient.Connect((LPCTSTR)szIP, 800))
{
AfxMessageBox(“连接到对方机器失败!”);
return;
}

SOCKET_STREAM_FILE_INFO StreamFileInfo;
sockClient.Receive(&StreamFileInfo, sizeof(SOCKET_STREAM_FILE_INFO));

CFile destFile(StreamFileInfo.szFileTitle, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);

UINT dwRead = 0;
while (dwRead<StreamFileInfo.nFileSizeLow)
{
    byte* data = new byte[1024];
    memset(data, 0, 1024);

    UINT dw = sockClient.Receive(data, 1024);
    destFile.Write(data, dw);

    dwRead += dw;
}

SetFileTime((HANDLE)destFile.m_hFile, &StreamFileInfo.ftCreationTime,
    &StreamFileInfo.ftLastAccessTime, &StreamFileInfo.ftLastWriteTime);
destFile.Close();
SetFileAttributes(StreamFileInfo.szFileTitle, StreamFileInfo.dwFileAttributes);
::closesocket(sockClient);
AfxMessageBox("接收完毕!");

}

Server实现
///////////////////////////////////////////
// TCPServer.h文件

#include <afxwin.h>     // 10TCPServer  
#include <afxcmn.h>
#include <winsock2.h> 

// 告诉连接器与WS2_32库连接
#pragma comment(lib,"WS2_32.lib")

#define MAX_SOCKET 56   // 定义此服务器所能接受的最大客户量

class CMyApp : public CWinApp
{
public:
    BOOL InitInstance();
};

class CMainDialog : public CDialog
{
public:
    CMainDialog(CWnd* pParentWnd = NULL);

protected:
    // 创建套节字,并设置为监听状态,准备接受客户的连接
    BOOL CreateAndListen(int nPort);
    // 关闭所有套节字,包括监听套节字和所有accept函数返回的套节字
    void CloseAllSocket();
    // 向客户连接列表中添加一个客户
    BOOL AddClient(SOCKET s, CString list2);
    // 从客户连接列表中移处一个客户
    void RemoveClient(SOCKET s);

protected:
    // 两个子窗口控件,一个是状态栏,一个是列表框
    CStatusBarCtrl m_bar;
    CListBox m_listInfo;

    // 监听套节字句柄
    SOCKET m_socket;
    CString clients[MAX_SOCKET];

    // 客户连接列表
    SOCKET m_arClient[MAX_SOCKET];  // 套节字数组
    int m_nClient;          // 上述数组的大小

protected:
    virtual BOOL OnInitDialog();
    virtual void OnCancel();
    // 开启或停止服务
    afx_msg void OnStart();
    // 清空信息
    afx_msg void OnClear();
    // 套节字通知事件
    afx_msg long OnSocket(WPARAM wParam, LPARAM lParam);

    //发送文件
    afx_msg void OnSendFile();



    DECLARE_MESSAGE_MAP()
};

/
// TCPServer.cpp文件

include “TCPClient.h”

include “resource.h”

include “ZMySocket.h”

include

include “afxdlgs.h”

include

define WM_SOCKET WM_USER + 1

typedef enum
{
USERNAME = 10,
MESSAGE = 20,
QUIT = 30,
SENDFILE = 40,
BURR = 60
}SendFlags;

typedef struct _SOCKET_STREAM_FILE_INFO {

SendFlags   sendflags;
TCHAR       szFileTitle[128];                   //文件的标题名
DWORD       dwFileAttributes;                   //文件的属性
FILETIME    ftCreationTime;                     //文件的创建时间
FILETIME    ftLastAccessTime;                   //文件的最后访问时间
FILETIME    ftLastWriteTime;                    //文件的最后修改时间
DWORD       nFileSizeHigh;                      //文件大小的高位双字
DWORD       nFileSizeLow;                       //文件大小的低位双字
DWORD       dwReserved0;                        //保留,为0
DWORD       dwReserved1;                        //保留,为0
UINT  dw;
char text[1024];
byte     fileBuffer[10240];

} SOCKET_STREAM_FILE_INFO, *PSOCKET_STREAM_FILE_INFO;

typedef struct
{
SendFlags sendflags;
char username[64];
char ipaddress[64];
char buffer[1024];
UINT dw;
byte fileBuffer[1024];
}Message;
/
CString str;
CFile* destFile;
UINT dwRead = 0;
TCHAR szFileTitle1[128]; //文件的标题名
DWORD dwFileAttributes1; //文件的属性
FILETIME ftCreationTime1; //文件的创建时间
FILETIME ftLastAccessTime1; //文件的最后访问时间
FILETIME ftLastWriteTime1; //文件的最后修改时间
DWORD nFileSizeHigh1; //文件大小的高位双字
DWORD nFileSizeLow1; //文件大小的低位双字

CMyApp theApp;
BOOL CMyApp::InitInstance()
{
// 初始化Winsock库

WSADATA wsaData;
WORD sockVersion = MAKEWORD(2, 0);
::WSAStartup(sockVersion, &wsaData);
// 弹出主窗口对话框
CMainDialog dlg;
m_pMainWnd = &dlg;
dlg.DoModal();
// 释放Winsock库
::WSACleanup();
return FALSE;

}

CMainDialog::CMainDialog(CWnd* pParentWnd):CDialog(IDD_MAINDIALOG, pParentWnd)
{
}

BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
ON_BN_CLICKED(IDC_START, OnStart)
ON_BN_CLICKED(IDC_CLEAR, OnClear)
ON_MESSAGE(WM_SOCKET, OnSocket)
END_MESSAGE_MAP()

BOOL CMainDialog::OnInitDialog()
{
CDialog::OnInitDialog();
// 设置图标
SetIcon(theApp.LoadIcon(IDI_MAIN), FALSE);
// 创建状态栏,设置它的属性
m_bar.Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP, CRect(0, 0, 0, 0), this, 101);
m_bar.SetBkColor(RGB(0xa6, 0xca, 0xf0)); // 背景色
int arWidth[] = { 200, -1 };
m_bar.SetParts(2, arWidth); // 分栏
m_bar.SetText(“”, 1, 0); // 第一个栏的文本
m_bar.SetText(” 空闲”, 0, 0); // 第二个栏的文本
// 设置列表框控件到m_listInfo对象的关联
m_listInfo.SubclassDlgItem(IDC_INFO, this);

// 初始化监听套节字和连接列表
m_socket = INVALID_SOCKET;
m_nClient = 0;

    // 下面是取得本地IP地址的过程,将它显示在状态栏的第一个分栏中
// 取得本机名称   
char szHost[256];
::gethostname(szHost, 256);
// 通过本机名称取得地址信息
HOSTENT* pHost = gethostbyname(szHost);
if(pHost != NULL)
{   
    CString sIP;

    // 得到第一个IP地址
    in_addr *addr =(in_addr*) *(pHost->h_addr_list);

    // 显示给用户
    sIP.Format(" 本机IP:%s", inet_ntoa(addr[0]));
    m_bar.SetText(sIP, 0, 0);
}

return TRUE;

}

void CMainDialog::OnStart()
{
if(m_socket == INVALID_SOCKET) // 开启服务
{
// 取得端口号
CString sPort;
GetDlgItem(IDC_PORT)->GetWindowText(sPort);
int nPort = atoi(sPort);
if(nPort < 1 || nPort > 65535)
{
MessageBox(“端口号错误!”);
return;
}

    // 创建监听套节字,使它进入监听状态
    if(!CreateAndListen(nPort))
    {
        MessageBox("启动服务出错!");
        return;
    }

    // 设置相关子窗口控件状态
    GetDlgItem(IDC_START)->SetWindowText("停止服务");
    m_bar.SetText(" 正在监听……", 0, 0);
    GetDlgItem(IDC_PORT)->EnableWindow(FALSE);

}
else                // 停止服务
{
    // 关闭所有连接
    CloseAllSocket();

    // 设置相关子窗口控件状态
    GetDlgItem(IDC_START)->SetWindowText("开启服务");
    m_bar.SetText(" 空闲", 0, 0);
    GetDlgItem(IDC_PORT)->EnableWindow(TRUE);
}

}

void CMainDialog::OnCancel()
{
CloseAllSocket();
CDialog::OnCancel();
}

void CMainDialog::OnClear()
{
m_listInfo.ResetContent();
}

long CMainDialog::OnSocket(WPARAM wParam, LPARAM lParam)
{
// 取得有事件发生的套节字句柄
SOCKET s = wParam;
// 查看是否出错
if(WSAGETSELECTERROR(lParam))
{
RemoveClient(s);
::closesocket(s);
return 0;
}
// 处理发生的事件
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT: // 监听中的套接字检测到有连接进入
{
if(m_nClient < MAX_SOCKET)
{
sockaddr_in remoteAddr;
int nAddrLen = sizeof(remoteAddr);
// 接受连接请求,新的套节字client是新连接的套节字
SOCKET client = ::accept(s, (SOCKADDR*)&remoteAddr, &nAddrLen);
// 设置新的套节字为窗口通知消息类型
int i = ::WSAAsyncSelect(client,
m_hWnd, WM_SOCKET, FD_READ|FD_WRITE|FD_CLOSE);

            CString list = inet_ntoa(remoteAddr.sin_addr);
            DWORD dwIP = ::inet_addr(list);
            // 获取主机名称,注意其中第一个参数的转化
            hostent* pHost = ::gethostbyaddr((LPSTR)&dwIP, 4, AF_INET);
            char szHostName[256];
            strncpy(szHostName, pHost->h_name, 256);
            CString list2 ="1" + CString(szHostName) + ":" + list+"\r\n";
            AddClient(client,list2);
            for (i = 0; i < m_nClient; i++)
            {
                for (int j = 0; j < m_nClient;j++)
                ::send(m_arClient[i], clients[j], clients[j].GetLength(), 0);
            }



        }
        else
        {
            MessageBox("连接客户太多!");
        }




    }
    break;

case FD_CLOSE:      // 检测到套接字对应的连接被关闭。
    {
        RemoveClient(s);
        ::closesocket(s);

        for (int i = 0; i < m_nClient; i++)
        {
            for (int j = 0; j < m_nClient; j++)
                ::send(m_arClient[i], clients[j], clients[j].GetLength(), 0);
        }

    }
    break;

case FD_READ:       // 套接字接受到对方发送过来的数据包
    {
                        int      nReceive;
                        Message  message;
                        // 取得对方的IP地址和端口号(使用getpeername函数)
                        // Peer对方的地址信息
                        sockaddr_in sockAddr;
                        memset(&sockAddr, 0, sizeof(sockAddr));
                        int nSockAddrLen = sizeof(sockAddr);
                        ::getpeername(s, (SOCKADDR*)&sockAddr, &nSockAddrLen);
                        // 转化为主机字节顺序
                        int nPeerPort = ::ntohs(sockAddr.sin_port);
                        // 转化为字符串IP
                        CString sPeerIP = ::inet_ntoa(sockAddr.sin_addr);

                        // 取得对方的主机名称
                        // 取得网络字节顺序的IP值
                        DWORD dwIP = ::inet_addr(sPeerIP);
                        // 获取主机名称,注意其中第一个参数的转化
                        hostent* pHost = ::gethostbyaddr((LPSTR)&dwIP, 4, AF_INET);
                        char szHostName[256];
                        strncpy(szHostName, pHost->h_name, 256);




                        SOCKET_STREAM_FILE_INFO     StreamFileInfo;


                        ::memset(&StreamFileInfo, '\0', sizeof(StreamFileInfo));
                        //socket的消息放入message中
                        if (::recv(s, (LPSTR)&StreamFileInfo, sizeof(StreamFileInfo), 0) != 0)
                        {
                            CString fromIp = sPeerIP;

                            if (StreamFileInfo.sendflags == SENDFILE)
                            {



                                CFile destFile2(StreamFileInfo.szFileTitle, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
                                ftCreationTime1 = StreamFileInfo.ftCreationTime;
                                ftLastAccessTime1 = StreamFileInfo.ftLastAccessTime;
                                ftLastWriteTime1 = StreamFileInfo.ftLastWriteTime;
                                strcpy(szFileTitle1, StreamFileInfo.szFileTitle);
                                dwFileAttributes1 = StreamFileInfo.dwFileAttributes;
                                nFileSizeLow1 = StreamFileInfo.nFileSizeLow;
                                destFile2.Write(StreamFileInfo.fileBuffer, StreamFileInfo.dw);
                                /*
                                while (dwRead<StreamFileInfo.nFileSizeLow)
                                {
                                    ::memset(&message, '\0', sizeof(message));
                                    recv(s,(LPSTR)&message, sizeof(message), 0);
                                    destFile.Write(message.fileBuffer, message.dw);
                                    dwRead += message.dw;
                                }

                                AfxMessageBox("不懂");
                                SetFileTime((HANDLE)destFile.m_hFile, &StreamFileInfo.ftCreationTime,
                                    &StreamFileInfo.ftLastAccessTime, &StreamFileInfo.ftLastWriteTime);
                                destFile.Close();
                                SetFileAttributes(StreamFileInfo.szFileTitle, StreamFileInfo.dwFileAttributes);
                                CString a = " 接收到来自IP:" + fromIp + "的文件:" + (CString)StreamFileInfo.szFileTitle;
                                AfxMessageBox(a);
                                */
                                SetFileTime((HANDLE)destFile2.m_hFile, &StreamFileInfo.ftCreationTime,
                                    &StreamFileInfo.ftLastAccessTime, &StreamFileInfo.ftLastWriteTime);
                                destFile2.Close();
                                SetFileAttributes(StreamFileInfo.szFileTitle, StreamFileInfo.dwFileAttributes);
                                CString a = " 接收到来自IP:" + fromIp + "的文件:" + (CString)StreamFileInfo.szFileTitle;
                                AfxMessageBox(a);



                            }

                            else if (StreamFileInfo.sendflags == MESSAGE)
                            {

                                char szText[1024] = { 0 };
                                for (int i = 0; i < 1024; i++)
                                {
                                    szText[i] = StreamFileInfo.text[i];
                                }
                                //strcpy(szText, StreamFileInfo.text);
                                    CString szText2 = (CString)szText;
                                    int pos = szText2.Find(' ');
                                    CString left = szText2.Left(pos);
                                    int len = szText2.GetLength() - pos;
                                    len--;
                                    CString szText3 = szText2.Right(len);
                                    // 显示给用户
                                    CString strItem = CString(szHostName) + "[" + sPeerIP + "]: " + CString(szText3);

                                    //OK
                                    int i;
                                    pos = left.Find(',');
                                    CString list;
                                    while (pos > 0)
                                    {
                                        list = left.Left(pos);
                                        len = left.GetLength() - pos;
                                        len--;
                                        left = left.Right(len);
                                        pos = left.Find(',');
                                        i = atoi((LPCTSTR)list);
                                        i = m_nClient - 1 - i;
                                        ::send(m_arClient[i], strItem, strItem.GetLength(), 0);

                                    }

                                    m_listInfo.InsertString(0, strItem);

                            }
                        }
                        else
                        {
                            AfxMessageBox("连接失败");
                        }







        ///
                        /*
            // 取得对方的IP地址和端口号(使用getpeername函数)
        // Peer对方的地址信息
        sockaddr_in sockAddr;
        memset(&sockAddr, 0, sizeof(sockAddr));
        int nSockAddrLen = sizeof(sockAddr);
        ::getpeername(s, (SOCKADDR*)&sockAddr, &nSockAddrLen);
        // 转化为主机字节顺序
        int nPeerPort = ::ntohs(sockAddr.sin_port);
        // 转化为字符串IP
        CString sPeerIP = ::inet_ntoa(sockAddr.sin_addr);

            // 取得对方的主机名称
        // 取得网络字节顺序的IP值
        DWORD dwIP = ::inet_addr(sPeerIP);
        // 获取主机名称,注意其中第一个参数的转化
        hostent* pHost = ::gethostbyaddr((LPSTR)&dwIP, 4, AF_INET);
        char szHostName[256];
        strncpy(szHostName, pHost->h_name, 256);         

        // 接受真正的网络数据
        char szText[1024] = { 0 };
        ::recv(s, szText, 1024, 0);
        if (szText[0] == '9'&&szText[1] == '9')
        {

        }
        else
        {
            CString szText2 = (CString)szText;
            int pos = szText2.Find(' ');
            CString left = szText2.Left(pos);
            int len = szText2.GetLength() - pos;
            len--;
            CString szText3 = szText2.Right(len);
            // 显示给用户
            CString strItem = CString(szHostName) + "[" + sPeerIP + "]: " + CString(szText3);

            //OK
            int i;
            pos = left.Find(',');
            CString list;
            while (pos > 0)
            {
                list = left.Left(pos);
                len = left.GetLength() - pos;
                len--;
                left = left.Right(len);
                pos = left.Find(',');
                i = atoi((LPCTSTR)list);
                i = m_nClient - 1 - i;
                ::send(m_arClient[i], strItem, strItem.GetLength(), 0);

            }

            m_listInfo.InsertString(0, strItem);
        }


        */


    }
    break;
}
return 0;

}

BOOL CMainDialog::CreateAndListen(int nPort)
{
if(m_socket == INVALID_SOCKET)
::closesocket(m_socket);

// 创建套节字
m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(m_socket == INVALID_SOCKET)
    return FALSE;

// 填写要关联的本地地址
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(nPort);
sin.sin_addr.s_addr = INADDR_ANY;
// 绑定端口
if(::bind(m_socket, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
{
    return FALSE;
}

// 设置socket为窗口通知消息类型
::WSAAsyncSelect(m_socket, m_hWnd, WM_SOCKET, FD_ACCEPT|FD_CLOSE);
// 进入监听模式
::listen(m_socket, 5);

return TRUE;

}

BOOL CMainDialog::AddClient(SOCKET s, CString list2)
{
if(m_nClient < MAX_SOCKET)
{
// 添加新的成员
m_arClient[m_nClient] = s;
clients[m_nClient++] = list2;
return TRUE;
}
return FALSE;
}

void CMainDialog::RemoveClient(SOCKET s)
{
BOOL bFind = FALSE;
int i;
for(i=0; i

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值