多线程+Socket+MFC界面库实现CS模式的云盘系统

功能:CS 模式文件上传、下载服务器 + 客户端(轻量级的个人云盘系统)

使用方法:

保证文件夹路径E:\myLibForYunPan\data和E:\myLibForYunPan\download存在,分别用来存放上传和下载的文件。

打开服务器和客户端程序WffosSocketClient.exe和WffosSocketSever.exe

WffosSocketClient.exe界面内输入服务器地址,点击连接,可以上传、下载文件,并显示发送相关消息。

WffosSocketSever.exe界面内点击删除,可以删除文件,并显示发送相关消息。

由于博客不知道怎么上传压缩文件,所以本博客没有对应.exe,相关文件稍后上传百度网盘。(http://pan.baidu.com/s/1nuGmCg5)

以下为客户端和服务器端代码:

// WffosSocketClientDlg.cpp : 实现文件
//
#include "stdafx.h"

#include<iostream>
#include<fstream>
#include<string>
using namespace std;

#include "WffosSocketClient.h"
#include "WffosSocketClientDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

// 对话框数据
    enum { IDD = IDD_ABOUTBOX };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CWffosSocketClientDlg 对话框



CWffosSocketClientDlg::CWffosSocketClientDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(CWffosSocketClientDlg::IDD, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CWffosSocketClientDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    //upLoadHis------------------------------
    /*:CWffosSocketClientDlg.h
    CButton    m_connect;
    CButton    m_disconnect;
    CButton    m_upLoad;
    CEdit    m_severIP;
    CEdit    m_talk;
    CListCtrl    m_talkList;
    */
    DDX_Control(pDX, IDC_BUTTON1, m_connect);
    DDX_Control(pDX, IDC_BUTTON3, m_disconnect);
    DDX_Control(pDX, IDC_BUTTON2, m_upLoad);
    DDX_Control(pDX, IDC_BUTTON4, m_downLoad);
    DDX_Control(pDX, IDC_EDIT2, m_severIP);
    DDX_Control(pDX, IDC_EDIT3, m_talk);
    DDX_Control(pDX, IDC_EDIT1, m_talkD);
    DDX_Control(pDX, IDC_LIST1, m_talkList);
    DDX_Control(pDX, IDC_LIST2, m_talkListD);
    //e------------------------------
}

BEGIN_MESSAGE_MAP(CWffosSocketClientDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //s--------------------changed
    ON_BN_CLICKED(IDC_BUTTON1, &CWffosSocketClientDlg::OnBnClickedConnect)
    ON_BN_CLICKED(IDC_BUTTON3, &CWffosSocketClientDlg::OnBnClickedDisconnect)
    ON_BN_CLICKED(IDC_BUTTON2, &CWffosSocketClientDlg::OnBnClickedUpLoad)
    ON_BN_CLICKED(IDC_BUTTON4, &CWffosSocketClientDlg::OnBnClickedDownLoad)
    //e-----------------------------
END_MESSAGE_MAP()


// CWffosSocketClientDlg 消息处理程序

BOOL CWffosSocketClientDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);            // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    // TODO:  在此添加额外的初始化代码
    //s------------------------------------------------------
    m_talk.SetLimitText(1024);
    m_talkD.SetLimitText(1024);
    m_talkD.SetWindowTextA("");//初始化下载输入框
    m_talkList.InsertColumn(0, "上传和下载信息");
    m_talkListD.InsertColumn(0, "可下载列表");
    m_talkList.SetColumnWidth(0, 435);
    m_talkListD.SetColumnWidth(0, 435);
    m_upLoad.EnableWindow(FALSE);
    m_downLoad.EnableWindow(FALSE);
    m_disconnect.EnableWindow(FALSE);
    m_severIP.SetWindowTextA("127.0.0.1");
    count = 0;
    //e-------------------------------------------------------
    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CWffosSocketClientDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CWffosSocketClientDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        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;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CWffosSocketClientDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}


//连接------------nameChanged
void CWffosSocketClientDlg::OnBnClickedConnect()
{
    // TODO:  在此添加控件通知处理程序代码
    /*:CWffosSocketClientDlg.h
    SOCKET clientSocket;
    sockaddr_in cliAdd;
    int count, cliFlag;
    */
    m_talkD.SetWindowTextA("");//初始化下载输入框
    char ipAddr[35];
    m_severIP.GetWindowTextA(ipAddr, 30);//项目->常规->使用多字符集
    //以下三行确定套接字
    cliAdd.sin_addr.s_addr = inet_addr(ipAddr);//_WINSOCK_DEPRECATED_NO_WARNINGS
    cliAdd.sin_family = AF_INET;
    cliAdd.sin_port = 5000;
    //创建套接字
    clientSocket = socket(AF_INET, SOCK_STREAM, 0);//三种套接字,SOCK_STREAM对应TCP/IP
    cliFlag = 1;//表示客户端准备完毕
    //启动线程
    AfxBeginThread(thread, 0);
}

//断开------------nameChanged
void CWffosSocketClientDlg::OnBnClickedDisconnect()
{
    // TODO:  在此添加控件通知处理程序代码
    cliFlag = 0;
    closesocket(clientSocket);
}

//上传-----------nameChanged
void CWffosSocketClientDlg::OnBnClickedUpLoad()
{
    // TODO:  在此添加控件通知处理程序代码
    char buff[1024];
    CSize size;
    size.cx = 0;
    size.cy = 30;
    m_talk.GetWindowTextA(buff, 1024);//获取输入的文件路径存于src
    string src = buff;
    ifstream in(src, ifstream::in);
    if (!in)
    {
        m_talkList.InsertItem(count++, "上传不成功,无法打开输入文件");
        return;
    }
    for (unsigned int i = 0; i < src.size(); i++)
    {
        if ('\\' == src[i])
            src[i] = '/';
    }
    string src1;
    src1.push_back(src[0]);
    for (unsigned int i = 1; i < src.size(); i++)
    {
        if ('/' == src[i])
        {
            if ('/' != src[i - 1])
                src1.push_back(src[i]);
        }
    }
    unsigned int j = 0;
    for (unsigned int i = 0; i < src.size(); i++)
    {
        if ('/' == src[i])
            j = i > j ? i : j;
    }
    string fName = src;
    fName.erase(0, j + 1);//去掉路径,保留文件名
    src = src1 + fName;
    send(clientSocket, ("#upld#" + src).c_str(), 1024, 0);//发送上传文件名
    //下面代码逐行上传
    string fLine;
    while (getline(in, fLine))
    {
        send(clientSocket, fLine.c_str(), 1024, 0);
    }
    send(clientSocket, "", 1024, 0);
    in.close();//必须有这一步
}

//下载-----------nameChanged
void CWffosSocketClientDlg::OnBnClickedDownLoad()
{
    // TODO:  在此添加控件通知处理程序代码
    char buff[1024];
    CSize size;
    size.cx = 0;
    size.cy = 30;
    m_talkD.GetWindowTextA(buff, 1024);//获取输入的文件路径存于src
    string src = buff;
    src = "E:/myLibForYunPan/data/" + src;
    send(clientSocket, ("#dnld#" + src).c_str(), 1024, 0);//发送下载文件名
}

//接收数据线程:
//当用户单击“连接”按钮以后
//程序进行相关设定
//最后调用了"AfxBeginThread(thread, 0);"启动了该线程
UINT thread(LPVOID v)
{
    char buff[1024];
    char array[25][30] =
    { "155.245.160.151",
    "155.245.160.152",
    "155.245.160.153",
    "155.245.160.154",
    "155.245.160.155",
    "155.245.160.156",
    "155.245.160.157",
    "155.245.160.158",
    "155.245.160.159",
    "155.245.160.160",
    "155.245.160.161",
    "155.245.160.162",
    "155.245.160.163",
    "155.245.160.164",
    "155.245.160.165",
    "155.245.160.166",
    "155.245.160.167",
    "155.245.160.168",
    "155.245.160.169",
    "155.245.160.170",
    "155.245.160.171",
    "155.245.160.172",
    "155.245.160.173",
    "155.245.160.174",
    "155.245.160.175" };// 定义数组用来存放一些IP地址
    CSize size;
    size.cx = 0;
    size.cy = 30;
    int socSta = 1, addcount = 0;
    CWffosSocketClientDlg *dlg = (CWffosSocketClientDlg*)AfxGetApp()->GetMainWnd();//获得当前运行对话
    dlg->m_connect.EnableWindow(FALSE);
    dlg->m_disconnect.EnableWindow(TRUE);
    //连接到服务器
    while (connect(dlg->clientSocket, (sockaddr*)&(dlg->cliAdd), sizeof(dlg->cliAdd)) && dlg->cliFlag != 0)
    {
        dlg->m_talk.SetWindowText("等待.....");
        //空循环
        for (int i = 0; i <= 65000; i++)
            for (int j = 0; j <= 200; j++);
        if (addcount == 25)
            addcount = 0;
        dlg->cliAdd.sin_addr.s_addr = inet_addr(array[addcount++]);
    }

    if (dlg->cliFlag == 1)//连接成功,则提示并允许上传下载
    {
        dlg->m_talkList.InsertItem(dlg->count++, "连接成功");
        dlg->m_upLoad.EnableWindow(TRUE);//允许上传数据
        dlg->m_downLoad.EnableWindow(TRUE);//允许下载数据
        dlg->m_talkListD.DeleteAllItems();
        dlg->SetForegroundWindow();
    }
        
    //连接建好以后,循环获得数据并显示
    while (socSta != SOCKET_ERROR && dlg->cliFlag != 0)
    {
        socSta = recv(dlg->clientSocket, buff, 1024, 0);//调用recv函数接收数据
        dlg->SetForegroundWindow();
        if (socSta != SOCKET_ERROR && dlg->cliFlag != 0)
        {
            string src = buff;
            string srcBegin = { buff[0], buff[1], buff[2], buff[3], buff[4], buff[5] };
            if ("#talk#" == srcBegin)//聊天消息
            {
                src.erase(0, 6);//去掉标记
                dlg->m_talkList.InsertItem(dlg->count++, src.c_str());
                dlg->m_talkList.Scroll(size);// Forces the control to scroll its client area by the specified amount.            
            }
            if ("#okdl#" == srcBegin)//可下载文件名显示
            {
                src.erase(0, 6);//去掉标记
                dlg->m_talkListD.InsertItem(dlg->count++, src.c_str());
            }
            if ("#dnld#" == srcBegin)
            {
                src.erase(0, 6);//去掉标记
                unsigned int j = 0;
                for (unsigned int i = 0; i < src.size(); i++)
                {
                    if ('/' == src[i])
                        j = i > j ? i : j;
                }
                string fName = src;
                fName.erase(0, j + 1);//去掉路径,保留文件名
                string dest = "E:/myLibForYunPan/download/" + fName;//目的文件路径记为dest
                ofstream toDest(dest, ofstream::out);//先打开一次,没有就创建,有就清除内容
                toDest.close();
                string msg = src + "下载到E:/myLibForYunPan/download/" + fName;
                ofstream downLoadSrcToDestHis("E:/myLibForYunPan/downLoadSrcToDestHis.txt", ofstream::app);
                downLoadSrcToDestHis << msg << endl;//写入上传源和目的信息到"E:/myLibForYunPan/downLoadSrcToDestHis.txt"
                dlg->m_talkList.InsertItem(dlg->count++, msg.c_str());
            }
            if (("#talk#" != srcBegin) && ("#okdl#" != srcBegin) && ("#dnld#" != srcBegin))
            {
                string dest = "E:/myLibForYunPan/download/";
                char fName[1024];
                dlg->m_talkD.GetWindowTextA(fName, 1024);
                dest = dest + fName;
                ofstream toDest(dest, ofstream::app);
                toDest << src << endl;//下面代码复制传过来的src信息到dest
                toDest.close();
            }
        }    
    }
    //非上述情况,则发送断开命令并终止线程
    send(dlg->clientSocket, "Disconnected", 1024, 0);
    dlg->m_upLoad.EnableWindow(FALSE);
    dlg->m_downLoad.EnableWindow(FALSE);
    dlg->m_connect.EnableWindow(TRUE);
    dlg->m_disconnect.EnableWindow(FALSE);
    closesocket(dlg->clientSocket);
    AfxEndThread(0);//终止该线程

    return 0;
}
View Code
// WffosSocketSeverDlg.cpp : 实现文件
//

#include "stdafx.h"

#include<iostream>
#include<fstream>
#include<string>
#include<Windows.h>
#include<stdio.h>
using namespace std;

#include "WffosSocketSever.h"
#include "WffosSocketSeverDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

// 对话框数据
    enum { IDD = IDD_ABOUTBOX };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CWffosSocketSeverDlg 对话框



CWffosSocketSeverDlg::CWffosSocketSeverDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(CWffosSocketSeverDlg::IDD, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CWffosSocketSeverDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    //s-------------------------------------
    /*:CWffosSocketSeverDlg.h
    CButton    m_delete;
    CListCtrl    m_talkList;
    CEdit    m_talk;
    */
    DDX_Control(pDX, IDC_BUTTON2, m_delete);
    DDX_Control(pDX, IDC_EDIT1, m_talk);
    DDX_Control(pDX, IDC_LIST1, m_talkList);
    DDX_Control(pDX, IDC_LIST2, m_talkListD);
}

BEGIN_MESSAGE_MAP(CWffosSocketSeverDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BUTTON2, &CWffosSocketSeverDlg::OnBnClickedDelete)
END_MESSAGE_MAP()


// CWffosSocketSeverDlg 消息处理程序

BOOL CWffosSocketSeverDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);            // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    // TODO:  在此添加额外的初始化代码
    //s-----------------------------------------------
    count = 0;
    m_talkList.InsertColumn(0, "上传下载消息");
    m_talkList.SetColumnWidth(0, 435);
    m_talkListD.InsertColumn(0, "已上传列表");
    m_talkListD.SetColumnWidth(0, 435);
    m_talk.SetLimitText(1024);
    for (int i = 0; i<50; i++)
        msgsock[i] = NULL;

    //设定地址
    servAdd.sin_addr.s_addr = htonl(INADDR_ANY);
    servAdd.sin_family = AF_INET;
    servAdd.sin_port = 5000;//htons(5000);
    addlen = sizeof(servAdd);
    m_delete.EnableWindow(TRUE);
    //创建socket
    sock = socket(AF_INET, SOCK_STREAM, 0);
    //绑定
    if (bind(sock, (sockaddr*)&servAdd, addlen))
    {
        m_talk.SetWindowTextA("绑定错误");
    }
    else
    {
        //m_talkList.InsertItem(count++,inet_ntoa(servAdd.sin_addr));
        m_talk.SetWindowTextA("");
        //开始侦听    
        listen(sock, 5);
        //调用线程
        AfxBeginThread(&thread, 0);
    }
    talkListDRefsh();
    //e--------------------------------------------------
    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CWffosSocketSeverDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CWffosSocketSeverDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessageA(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        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;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CWffosSocketSeverDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}

//删除
void CWffosSocketSeverDlg::OnBnClickedDelete()
{
    // TODO:  在此添加控件通知处理程序代码
    char buff[1024];
    CSize size;
    size.cx = 0;
    size.cy = 30;
    m_talk.GetWindowTextA(buff, 1024);//获取输入的文件路径存于buff
    string src = buff;
    src = "E:/myLibForYunPan/data/" + src;
    ifstream in(src);
    if (!in)
    {
        m_talkList.InsertItem(count++, "删除不成功,无法打开该文件");
        return;
    }
    in.close();//必须有这一步,不关闭无法删除

    if (DeleteFileA(src.c_str()))
    {
        string BKFName = "BKupLoadDestHis.txt";
        BKFName = "E:/myLibForYunPan/" + BKFName;//备份文件路径BKFName

        string upLoadDestHisList;
        ifstream upLoadDestHis("E:/myLibForYunPan/upLoadDestHis.txt", ifstream::in);
        while (getline(upLoadDestHis, upLoadDestHisList))
        {
            string WriteBKFLine;
            ofstream WriteBKF(BKFName, ifstream::app);//新建备份文件
            if (upLoadDestHisList != src)
            {
                WriteBKF << upLoadDestHisList << endl;//写备份文件
            }
            WriteBKF.close();
        }
        upLoadDestHis.close();
        string ReadBKFLine;
        ifstream ReadBKF(BKFName, ifstream::in);
        string WriteupLoadDestHisLine;
        ofstream WriteupLoadDestHis("E:/myLibForYunPan/upLoadDestHis.txt", ofstream::out);
        m_talkList.InsertItem(count++, src.c_str());
        while (getline(ReadBKF, ReadBKFLine))
        {
            WriteupLoadDestHis << ReadBKFLine << endl;//备份拷贝到原文件
        }
        WriteupLoadDestHis.close();
        ReadBKF.close();
        DeleteFileA(BKFName.c_str());//删除备份文件
        const string END = "已删除";
        string msg = src + END;
        m_talkList.InsertItem(count++, msg.c_str());
        //循环向所有客户发送信息
        for (int i = 0; i<50; i++)
        {
            if (msgsock[i] != NULL)
                send(msgsock[i], ("#talk#" + msg).c_str(), 1024, 0);
        }
        talkListDRefsh();//有删除,刷新可删除列表
    }
    else
        m_talkList.InsertItem(count++, "删除不成功");
}

string dest;
bool upLoadFlag = TRUE;
bool downLoadFlag = TRUE;

const string TALK = "#talk#";//对话消息用"#talk#"标记
const string UPLD = "#upld#";//上传文件路径用"#upld#"标记
const string DNLD = "#dnld#";//下载文件路径用"#dnld#"标记

UINT thread(LPVOID p)
{
    char buff[1024];
    CSize size;
    size.cx = 0;
    size.cy = 30;
    int s = 1, msgcount, loop = 1, flag = 0;
    CWffosSocketSeverDlg *dlg = (CWffosSocketSeverDlg*)AfxGetApp()->GetMainWnd();
    //获得客户端数量
    msgcount = dlg->getcount();
    if (msgcount == -1)
        loop = 0;
    if (loop)
    {
        s = 1;
        dlg->msgsock[msgcount] = accept(dlg->sock, (sockaddr*)&(dlg->servAdd), &(dlg->addlen));
        if (dlg->msgsock[msgcount] == INVALID_SOCKET)
        {
            dlg->m_talk.SetWindowTextA("Error accept");
        }
        else
        {
            //启动线程
            AfxBeginThread(thread, 0);
            dlg->SetForegroundWindow();
            dlg->m_talkList.InsertItem(dlg->count++, "连接成功");
            dlg->m_talkList.InsertItem(dlg->count++, inet_ntoa(dlg->servAdd.sin_addr));//_WINSOCK_DEPRECATED_NO_WARNINGS
            dlg->m_talkList.Scroll(size);
            dlg->m_delete.EnableWindow(TRUE);

            //下面代码显示客户端可下载列表
            string upLoadDestHisLine;
            ifstream upLoadDestHis("E:/myLibForYunPan/upLoadDestHis.txt", ifstream::in);
            while (getline(upLoadDestHis, upLoadDestHisLine))
            {
                send(dlg->msgsock[msgcount], ("#okdl#" + upLoadDestHisLine).c_str(), 1024, 0);
            }
            upLoadDestHis.close();

            while (s != SOCKET_ERROR)
            {
                //循环接收数据
                s = recv(dlg->msgsock[msgcount], buff, 1024, 0);
                dlg->SetForegroundWindow();
                string src = buff;
                string srcBegin = { buff[0], buff[1], buff[2], buff[3], buff[4], buff[5] };
                if ("#talk#" == srcBegin)//对话消息用"#talk#"标记
                {
                    src.erase(0, 6);//去掉标记
                    dlg->m_talkList.InsertItem(dlg->count++, src.c_str());
                    dlg->m_talkList.Scroll(size);// Forces the control to scroll its client area by the specified amount.            
                }
                if ("#upld#" == srcBegin)//上传文件路径用"#upld#"标记
                {
                    src.erase(0, 6);//去掉标记
                    upLoadFlag = TRUE;//恢复默认
                    //------------------------------------------------------------
                    //下面代码检查是否上传过,服务器端是否删除对应文件,决定是否能上传
                    unsigned int j = 0;
                    for (unsigned int i = 0; i < src.size(); i++)
                    {
                        if ('/' == src[i])
                            j = i > j ? i : j;
                    }
                    string fName = src;
                    fName.erase(0, j + 1);//去掉路径,保留文件名
                    fName = "E:/myLibForYunPan/data/" + fName;//目的文件路径记为fName
                    ifstream RupLoadDest(fName, ifstream::in);
                    if (RupLoadDest)
                    {
                            upLoadFlag = FALSE;//上传过,不能再上传 
                    }
                    RupLoadDest.close();
                    
                    if (FALSE == upLoadFlag)
                    {
                        send(dlg->msgsock[msgcount], (TALK + "该文件上传过,不能再次上传").c_str(), 1024, 0);
                    }
                    //-----------------------------------------------------------
                    if (TRUE == upLoadFlag)//未上传过
                    {
                        ofstream WupLoadSrcHis("E:/myLibForYunPan/upLoadSrcHis.txt", ofstream::app);
                        WupLoadSrcHis << src << endl;//写入上传的文件名到"E:/myLibForYunPan/upLoadSrcHis.txt"
                        WupLoadSrcHis.close();
                        unsigned int j = 0;
                        for (unsigned int i = 0; i < src.size(); i++)
                        {
                            if ('/' == src[i])
                                j = i > j ? i : j;
                        }
                        string fName = src;
                        fName.erase(0, j + 1);//去掉路径,保留文件名
                        dest = "E:/myLibForYunPan/data/" + fName;//目的文件路径记为dest

                        ofstream WupLoadDestHis("E:/myLibForYunPan/upLoadDestHis.txt", ofstream::app);
                        WupLoadDestHis << dest << endl;//写入上传的文件名到"E:/myLibForYunPan/upLoadDestHis.txt"
                        WupLoadDestHis.close();
                        const string TO = "上传至";
                        string SrcToDestHis = src + TO + dest;//记录条
                        ofstream WupLoadSrcToDestHis("E:/myLibForYunPan/upLoadSrcToDestHis.txt", ofstream::app);
                        WupLoadSrcToDestHis << SrcToDestHis << endl;//写入上传源和目的信息到"E:/myLibForYunPan/upLoadSrcToDestHis.txt"
                        WupLoadSrcToDestHis.close();
                        dlg->m_talkList.InsertItem(dlg->count++, SrcToDestHis.c_str());
                        dlg->m_talkList.Scroll(size);// Forces the control to scroll its client area by the specified amount.            

                        send(dlg->msgsock[msgcount], (TALK + SrcToDestHis).c_str(), 1024, 0);//向客户发送信息
                    }
                    dlg->talkListDRefsh();//有新上传,刷新可删除列表
                }
                if ("#dnld#" == srcBegin)//下载文件路径用"#dnld#"标记
                {
                    src.erase(0, 6);//去掉标记
                    //下面代码检查是否可下载
                    ifstream RdownLoadSrc(src, ifstream::in);
                    if (!RdownLoadSrc)
                    {
                        downLoadFlag = FALSE;//该文件不存在,不能下载
                        send(dlg->msgsock[msgcount], (TALK + "该文件不存在,不能下载").c_str(), 1024, 0);//向客户端发送消息
                    }
                    else
                    {
                        downLoadFlag = TRUE;//该文件存在,能下载
                        send(dlg->msgsock[msgcount], ("#dnld#"+src).c_str(), 1024, 0);//向客户端发送消息
                        string downLoadSrcLine;
                        while (getline(RdownLoadSrc, downLoadSrcLine))
                        {
                            send(dlg->msgsock[msgcount], downLoadSrcLine.c_str(), 1024, 0);
                        }
                    }
                    RdownLoadSrc.close();
                }
                if (("#talk#" != srcBegin) && ("#upld#" != srcBegin) && ("#dnld#" != srcBegin) && (TRUE == upLoadFlag))
                {
                    ofstream toDest(dest, ofstream::app);
                    toDest << src << endl;//下面代码复制传过来的src信息到dest
                    toDest.close();
                }
                else
                    continue;
            }
            send(dlg->msgsock[msgcount], "#talk#Disconnected", 1024, 0);
            dlg->m_talkList.InsertItem(dlg->count++, "Disconnected");
            dlg->m_talkList.Scroll(size);
            dlg->msgsock[msgcount] = NULL;
            for (int i = 0; i < 50; i++)
                if (dlg->msgsock[i] != NULL)
                    flag = 1;
            if (flag != 1)
                dlg->m_delete.EnableWindow(FALSE);
            closesocket(dlg->msgsock[msgcount]);
        }
        //终止线程
        AfxEndThread(0);
        return 0;
    }
}

//获得还没有使用的socket数组号
int CWffosSocketSeverDlg::getcount()
{
    for (int i = 0; i<50; i++)
    {
        if (msgsock[i] == NULL)
            return i;
    }
    return -1;

}

void CWffosSocketSeverDlg::talkListDRefsh()
{
    m_talkListD.DeleteAllItems();
    string upLoadHistory;
    string upLoadedFile = "E:/myLibForYunPan/upLoadDestHis.txt";
    ifstream ifUpLoadedFile(upLoadedFile, ifstream::in);
    while (getline(ifUpLoadedFile, upLoadHistory))
    {
        CSize size;
        size.cx = 0;
        size.cy = 30;
        m_talkListD.InsertItem(count++, upLoadHistory.c_str());
        m_talkListD.Scroll(size);// Forces the control to scroll its client area by the specified amount.
    }
}

void CWffosSocketSeverDlg::cliTalkListDRefsh()
{
    //下面代码显示客户端可下载列表
    string upLoadDestHisLine;
    ifstream upLoadDestHis("E:/myLibForYunPan/upLoadDestHis.txt", ifstream::in);
    while (getline(upLoadDestHis, upLoadDestHisLine))
    {
        ifstream RupLoadDest(upLoadDestHisLine, ifstream::in);
        if (RupLoadDest)
        {
            for (int i = 0; i<50; i++)
            {
                if (msgsock[i] != NULL)
                    send(msgsock[i], ("#okdl#" + upLoadDestHisLine).c_str(), 1024, 0);
            }
        }
        RupLoadDest.close();
    }
    upLoadDestHis.close();
}
View Code

 

转载于:https://www.cnblogs.com/wffos/p/6727163.html

环境:Windows XP SP3、 VC++ 6.0、 Windows 2003 SDK 使用步骤: 1、下载解压之后,使用VC++ 6.0打开两个工程:一个是SocketServer和一个ClientSocket工程。 2、首先运行服务器端工程,选默认的端口1008 3、然后运行客户端工程,选默认的端口1008和默认的服务器地址 4、再运行多个客户端进程 5、如果一切正常,可以每个客户端的消息发送,我们可以在服务端和各个客户端同步看到消息 实现一个服务器对多个客户端的关键是,在服务端的使用集合CPtrList类用保存客户端的socket对象,思想与Java中的编程思想一样,只不过Java中会使用多线程技术,在Vector集合保存客户端的socket对象,而MFC框架提供了CSocket类,它是一个异步通信的类,所以看上去代码比较Java的多线程代码简单的实现了一个对多的即时通讯功能。另外,MFC提供了CSocketFile类和CArchive类与CSocket类实现了C++的网络通讯编程功能。 本示例注释非常详细,所有的辅助类都放一个util目录中,然后在工程中分了一个目录来管理这些辅助类,使用代码非常清晰。手动书写部分的代码是按Java的规范书写,当然其它代码由IDE生成的,所以是MS的风格,所以当你看代码时,只要是使用“骆驮命名法”的方法都是本人书写的功能性代码。 参看的思路:在服务端要从回调方法onAccept读起;而客户端代码主要从OnSendButton方法读起,即可理解整个代码的意思。 阅读对象:具有Java的Socket编程经验的人员,并且希望能够书写出比Java效率更高的即时通讯程序的人员
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值