⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpserverdlg.cpp

📁 多客户端与服务器(多线程)通信
💻 CPP
字号:
// TCPServerDlg.cpp : implementation file
//

#include "stdafx.h"
#include "TCPServer.h"
#include "TCPServerDlg.h"

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

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

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()

/////////////////////////////////////////////////////////////////////////////
// CTCPServerDlg dialog
#define PORT		34567
#define FLAG		2
#define FILENAMELEN 100
#define SIZEFILE	1024

CWinThread	*pThreadListen;		//监听线程-->_ListenTcpThread

UINT _ListenTcpThread(LPVOID lparam);

CTCPServerDlg::CTCPServerDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTCPServerDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CTCPServerDlg)
		// 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);
	m_isStop = true;
}

void CTCPServerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CTCPServerDlg)
	DDX_Control(pDX, IDC_HOSTIP, m_HostIP);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CTCPServerDlg, CDialog)
	//{{AFX_MSG_MAP(CTCPServerDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BTN_START, OnBtnStart)
	ON_BN_CLICKED(IDC_BTN_SHUTDOWN, OnBtnShutdown)
	ON_BN_CLICKED(IDC_BTN_SAVE, OnBtnSave)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTCPServerDlg message handlers

BOOL CTCPServerDlg::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_HostIP.EnableWindow(false);
	GetDlgItem(IDC_BTN_SHUTDOWN)->EnableWindow(false);//停止不可用
	GetDlgItem(IDC_BTN_SAVE)->EnableWindow(false);//保存文件不可用

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CTCPServerDlg::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 CTCPServerDlg::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 CTCPServerDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CTCPServerDlg::OnBtnStart() 
{
	// TODO: Add your control notification handler code here
	m_isStop = false;
	CString strLocalName;
	GetLocalHostName(strLocalName);
	CString strLocalIP;
	GetIpAddress(strLocalName,strLocalIP);
	m_HostIP.SetWindowText(strLocalIP);	//设置默认IP为本机

	((CEdit*)GetDlgItem(IDC_RECORD))->SetWindowText("服务器启动!\r\n");
	
	pThreadListen=::AfxBeginThread(_ListenTcpThread,this);	//开始TCP线程
	GetDlgItem(IDC_BTN_START)->EnableWindow(false);//开始可用
	GetDlgItem(IDC_BTN_SHUTDOWN)->EnableWindow(true);//停止可用
	
}

void CTCPServerDlg::OnBtnShutdown() 
{
	// TODO: Add your control notification handler code here
	m_isStop = true;
	m_HostIP.SetWindowText("");
	GetDlgItem(IDC_BTN_START)->EnableWindow(true);//开始可用
	GetDlgItem(IDC_BTN_SHUTDOWN)->EnableWindow(false);//停止可用
	GetDlgItem(IDC_BTN_SAVE)->EnableWindow(true);//停止可用
}

void CTCPServerDlg::OnBtnSave() 
{
	// TODO: Add your control notification handler code here

}

CString CTCPServerDlg::GetError(DWORD error)
{
	CString strError;
	switch(error)
	{
	case WSANOTINITIALISED:
		strError="初始化错误";
		break;
	case WSAENOTCONN:
		strError="对方没有启动";
		break;
	case WSAEWOULDBLOCK :
		strError="对方已经关闭";
		break;
	case WSAECONNREFUSED:
		strError="连接的尝试被拒绝";
		break;
	case WSAENOTSOCK:
		strError="在一个非套接字上尝试了一个操作";
		break;
	case WSAEADDRINUSE:
		strError="特定的地址已在使用中";
		break;
	case WSAECONNRESET:
		strError="与主机的连接被关闭";
		break;
	default:
		strError="一般错误";	
	}
	return strError;
}

int CTCPServerDlg::GetLocalHostName(CString &sHostName)
{
	char szHostName[256];
	int nRetCode;
	nRetCode=gethostname(szHostName,sizeof(szHostName));
	if(nRetCode!=0)
	{
		//产生错误
		sHostName=_T("获取主机名失败");
		return GetLastError();
	}
	sHostName=szHostName;
	return 0;
}

int CTCPServerDlg::GetIpAddress(const CString &sHostName, CString &sIpAddress)
{
	struct hostent FAR * lpHostEnt=gethostbyname(sHostName);
	if(lpHostEnt==NULL)
	{
		//产生错误
		sIpAddress=_T("");
		return GetLastError();
	}
	//获取IP
	LPSTR lpAddr=lpHostEnt->h_addr_list[0];
	if(lpAddr)
	{
		struct in_addr inAddr;
		memmove(&inAddr,lpAddr,4);
		//转换为标准格式
		sIpAddress=inet_ntoa(inAddr);
		if(sIpAddress.IsEmpty())
			sIpAddress=_T("没有取得");
	}
	return 0;
}

int CTCPServerDlg::GetNamebyAddress(const CString &IpAddress, CString &sYouName)
{
	unsigned long addr;
	addr=inet_addr(IpAddress);
	struct hostent FAR * lpHostEnt=gethostbyaddr((char *)&addr,4,AF_INET);
	if(lpHostEnt==NULL)
	{
		//产生错误
		sYouName=_T("");
		
		AfxMessageBox("连接不上");//应该取得其错误
		return -1;
	}
	CString name=lpHostEnt->h_name;
	sYouName=name;
	return 0;
}
int CTCPServerDlg::ReceiveFileMsg(CSocket &connectSock, SOCKADDR_IN &client,CString theFile)
{
	CFile myFile;
	int fileLen;
	CString oldStr;
	if(!myFile.Open(theFile, CFile::modeRead | CFile::typeBinary))  return -1;
	fileLen=myFile.GetLength();		//得到文件大小

	myFile.Seek(0,CFile::begin);

	char m_buf[SIZEFILE]={0};
	char buf[2]={0};

	CString strError;
	int numRead=0;
	int end=0;
	int temp=0;
	
	while(true)
	{
		numRead=myFile.Read(m_buf, SIZEFILE);
		if(numRead==0)  break; //文件读取到尽头

		end=connectSock.Send(m_buf, numRead); 
		connectSock.Receive(buf,2);  //保持相互通信,否则Client卡机,还不知道问什么

		temp+=end; //已发送了多少
		
		if(end==SOCKET_ERROR)
		{
			MessageBox("File Send Error!"+GetError(GetLastError()));
			break;
		}
	}
	connectSock.Send("O", 2); 
	if (temp==fileLen)
	{
		GetDlgItemText(IDC_RECORD,oldStr);
		oldStr = oldStr+"发送文件成功!"+"\r\n";
		SetDlgItemText(IDC_RECORD,oldStr);
	}
		
	else 
	{
		GetDlgItemText(IDC_RECORD,oldStr);
		oldStr = oldStr+"发送文件失败!"+"\r\n";
		SetDlgItemText(IDC_RECORD,oldStr);
	}
	myFile.Close();
	return 0;
}

CString CTCPServerDlg::Recurse(CString pstr,CString fileName) //寻找文件
{
	CFileFind finder;
	CString disk = pstr+fileName; //起始目录
	int bWorking = finder.FindFile(disk);
	if  (0==bWorking)	return "";
	else
	{
		finder.FindNextFile();
		return finder.GetFilePath();
	}
}

int CTCPServerDlg::TransportFile(CSocket &connectSock, SOCKADDR_IN &client)
{
	CString theFile="D:\\KwDownload\\lyric\\";
	char flag[500]={0};	
	CString oldStr;
	CString newStr(inet_ntoa(client.sin_addr));
	while(true)
	{
		int recvFlag = connectSock.Receive(flag,500);
		if (0==recvFlag)
		{
			return -1;
		}
		if (recvFlag==2&&flag[0]=='D')
		{
			GetDlgItemText(IDC_RECORD,oldStr);
			oldStr = oldStr+newStr+"断开连接:"+"\r\n";
			SetDlgItemText(IDC_RECORD,oldStr);
			return -1;
		}
		else if (recvFlag==2&&flag[0]=='Y')  //如果收到Y表示客户端接受传文件
		{
			GetDlgItemText(IDC_RECORD,oldStr);
			oldStr = oldStr+newStr+"客户端同意接收,开始传送"+"\r\n";
			SetDlgItemText(IDC_RECORD,oldStr);
			//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
			ReceiveFileMsg(connectSock,client,theFile);  //在这个函数中处理传送文件
			//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		}
		else if (recvFlag==2&&flag[0]=='N') //如果接收到N表示客户端拒绝接收文件
		{
			GetDlgItemText(IDC_RECORD,oldStr);
			oldStr = oldStr+newStr+"拒绝接收文件:"+"\r\n";
			SetDlgItemText(IDC_RECORD,oldStr);
			continue;
		}
		else
		{
			GetDlgItemText(IDC_RECORD,oldStr);
			oldStr = oldStr+newStr+"向服务器搜索:"+flag+"\r\n";
			SetDlgItemText(IDC_RECORD,oldStr);
			//connectSock.Send(flag,500); 
			// 开始搜索文件
			CString disk = "D:\\";
			CString fileName(flag);
			CString filePath = Recurse(disk,fileName);
			if (filePath.IsEmpty())
			{
				connectSock.Send("N",2); //表示没有要搜索的文件
				GetDlgItemText(IDC_RECORD,oldStr);
				oldStr = oldStr+"没有要搜索的文件:"+flag+"\r\n";
				SetDlgItemText(IDC_RECORD,oldStr);
			}
			else
			{
				memset(flag,0,500);
				CString fileInfo = "接收"+fileName+"?";
				memcpy(flag,fileInfo,sizeof(fileInfo));
				connectSock.Send(flag,500);  //到时候Client接收的不是N 表示有文件传送
				theFile = filePath;
			}
		}
		if (m_isStop==true)
		{
			connectSock.Send("D",2);
			return -1;
		}
		
	}
	
	return 0;
}

// Thread Function
UINT _ListenTcpThread(LPVOID lparam)
{
	CTCPServerDlg *pDlg=(CTCPServerDlg *)lparam;
	if(true==pDlg->m_isStop)	return -1;
	
	CSocket sockSrvr;
	
	int createSucceed=sockSrvr.Create(PORT);
	if(createSucceed==0)
	{
		AfxMessageBox("_ListenTcpThread Create Error!"+pDlg->GetError(GetLastError()));
		return -1;
	}
	//处于阻塞模式,当错误发生或者有连接时往下执行
	int listenSucceed=sockSrvr.Listen();	//开始监听
	if(listenSucceed==0)
	{
		AfxMessageBox("_ListenTcpThread Listen错误!"+pDlg->GetError(GetLastError()));
		return -1;
	}
	CSocket connectSock;

	SOCKADDR_IN client;
	int iAddrSize=sizeof(client);

	
	int acceptSucceed=sockSrvr.Accept(connectSock,(SOCKADDR *)&client,&iAddrSize);	//接受连接并取得对方IP
	if(acceptSucceed==0)
	{
		AfxMessageBox("_ListenTcpThread Accept Error!"+pDlg->GetError(GetLastError()));
		return -1;
	}
	//有连接出现
	sockSrvr.Close(); //服务器的Socket已经没用了,下面使用连接成功的connectSock进行通信
	//再重新开启一个相同的线程,因为这个线程要结束了
	pThreadListen=::AfxBeginThread(_ListenTcpThread,pDlg); 
	//在服务器的记录取记录连接事件
	CString oldStr;
	pDlg->GetDlgItemText(IDC_RECORD,oldStr);
	CString newStr(inet_ntoa(client.sin_addr));
	oldStr = oldStr+newStr+"连接到服务器上\r\n";
	pDlg->SetDlgItemText(IDC_RECORD,oldStr);

	pDlg->TransportFile(connectSock,client);

	return 0;
	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -