文档章节

基于Socket的文件传输(使用CSocket类)

雷霄骅
 雷霄骅
发布于 2014/08/16 13:58
字数 1795
阅读 142
收藏 0

本软件使用MFC采用面向对象的方法实现了基于Socket的文件传输。这是原来研究生课程的结课作业,实现了Socket的发送和接收,以及读取ini配置文件等操作。使用了CSocket类

以下是当时结课作业 的正文:

 

一.软件特点如下:

 

1.      采用了多线程的方法,文件传输时使用AfxBeginThread()开启新线程

 

void CClientsockDlg::OnBnClickedSend()

{

   pThreadSend = AfxBeginThread(Thread_Send,this);/

 }

 

文件的发送和接收都开起了新线程

 

UINTThread_Send(LPVOID lpParam)

{

   代码略

}

 

2.      支持从配置文件configuration.ini中获取服务器参数

 

采用GetPrivateProfileString()GetPrivateProfileInt()分别获取位于ServerConfiguration.ini文件中的String类型的IPint类型的port

CString IP;

int port;

GetPrivateProfileString

(L"ServerConfiguration",L"IP",L"没有读取到数据!",IP.GetBuffer(10),10,L".\\configuration.ini");

port=GetPrivateProfileInt(L"ServerConfiguration",L"port",0,L".\\configuration.ini");

                                                                                                            

 

3.      采用了面向对象的设计方式,功能之间按模块划分

MFC本身具有良好的面向对象的特性,本程序严格按照MFC框架结构编写代码,每个按钮对应一个功能函数,降低了代码之间的耦合性,有利于程序的扩展和复用。

 

void CServersockDlg::OnBnClickedChoose()

void CServersockDlg::OnBnClickedSend()

void CServersockDlg::OnBnClickedRecvdata()

void CServersockDlg::OnBnClickedAbout()

void CServersockDlg::OnBnClickedWriteini()

 

 

4.      采用了CSocket类,代码相对更简单

CSocket类是MFC框架对socket编程中的winsockAPI的封装,因此通过这个类管理收发数据更加便利。代码也跟那个既简单易懂。

        //创建

        if(!Clientsock.Socket())

        {

                  CString str;

                  str.Format(_T("Socket创建失败:%d"),GetLastError());

                  AfxMessageBox(str);

        }

        //连接

        if(!Clientsock.Connect(IP,port))

        {

                  CString str;

                  str.Format(_T("Socket连接失败:%d"),GetLastError());

                  AfxMessageBox(str);

        }

        else

        {

                  AfxMessageBox(_T("Socket连接成功"));

                代码略

        //发送

                  while(nSize<FindFileData.nFileSizeLow)

                  {

           szBuff = new char[1024];

                           memset(szBuff,0x00,1024);

                           nSend =file.Read(szBuff,1024);

                           Clientsock.Send(szBuff,nSend);//发送数据

                           nSize += nSend;

                  }

                  file.Close();

                  delete szBuff;

                  Clientsock.Close();

                  (dlg->GetDlgItem(IDC_SEND))->EnableWindow(TRUE);

                  AfxMessageBox(_T("文件发送成功"));

                  dlg->SetDlgItemTextW(IDC_FILEPATHNAME,_T(""));

        }

        return 0;

 

 

5.      支持数据在服务器与客户端之间双向传输

 

本程序不但可以从客户端往服务器端传文件,而且可以从服务器端往客户端传文件。

但是互传文件的方式并不是完全相同的。

服务器端不管是接收文件还是发送文件始终是对绑定的端口进行监听。

   //绑定

   if(!Serversock.Bind(port))

   {

       CString str;

      str.Format(_T("Socket绑定失败: %d"),GetLastError());

       AfxMessageBox(str);

   }

   //监听

   if(!Serversock.Listen(10))

   {

       CString str;

       str.Format(_T("Socket监听失败:%d"),GetLastError());

       AfxMessageBox(str);

   }

 

 

客户端不管是接收文件还是发送文件始终是进行连接。

   if(!Clientsock.Connect(IP,port))

   {

       CString str;

       str.Format(_T("Socket连接失&igrave;:%d"),GetLastError());

       AfxMessageBox(str);

   }

   else

   {

       

 

6.      完全图形化操作界面

 

 

二.软件使用说明

 

客户端主界面如图所示:

 

u 单击“选择文件”弹出文件对话框,选择一个要发送的文件,同时保存文件的路径。

u 单击“发送”则会读取ServerConfiguration.ini文件中的配置信息(IPport),并根据此信息建立Socket连接,发送文件。注意:服务器端应该先单击了“接受客户端数据”,否则发送失败。

u 单击“接收”也会读取ServerConfiguration.ini文件中的配置信息(IPport),并根据此信息建立Socket连接,接收文件。注意:服务器端应该先选择了向客户端发送的文件,并单击了“发送”,否则接受失败。

u 单击“读取配置文件”,会从ServerConfiguration.ini文件中读取配置信息,并以可编辑的文本形式显示出来,修改完后,单击“写入配置文件”,会将修改后的信息保存到配置文件中。

u 单击“关于”可以了解到软件相关信息。

u 代码注释里有更详细的说明

服务器端主界面如图所示

 

u 单击“接受客户端数据”,开始监听客户端的链接。

u  单击“选择文件”弹出文件对话框,选择一个要发送的文件,同时保存文件的路径。

u  单击“发送”则会读取ServerConfiguration.ini文件中的配置信息(port),并监听对应端口,准备发送文件。注意:客户端选择“接收”以后才能发送成功。

u  单击“读取配置文件”,会从ServerConfiguration.ini文件中读取配置信息,并以可编辑的文本形式显示出来,修改完后,单击“写入配置文件”,会将修改后的信息保存到配置文件中。但是服务器的IP是不可以修改的,它是在程序开始运行时从服务器所在机器的网卡上获取的。

u  单击“关于”可以了解到软件相关信息。

u  代码注释里有更详细的说明

 

 

 

 

 

代码下载地址:http://download.csdn.net/detail/leixiaohua1020/6320417

 

在此附上客户端使用CSocket发起连接的代码

//----------------------------发送文件的线程------------------------------
UINT Thread_Send(LPVOID lpParam)
{
	CClientsockDlg *dlg=(CClientsockDlg *)lpParam;
    (dlg->GetDlgItem(IDC_SEND))->EnableWindow(FALSE);

	CSocket Clientsock; //definition socket.
	if(!AfxSocketInit())
	{
		AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
	}

	CString IP;
	int port;
	GetPrivateProfileString(L"ServerConfiguration",L"IP",L"没有读取到数据!",IP.GetBuffer(100),100,L".\\configuration.ini");
	port=GetPrivateProfileInt(L"ServerConfiguration",L"port",0,L".\\configuration.ini");
	//创建
	if(!Clientsock.Socket())
	{
		CString str;
		str.Format(_T("Socket创建失败: %d"),GetLastError());
		AfxMessageBox(str);
	}
	//连接
//	if(!Clientsock.Connect(_T("127.0.0.1"),8088))
	if(!Clientsock.Connect(IP,port))
	{
		CString str;
		str.Format(_T("Socket连接失败: %d"),GetLastError());
		AfxMessageBox(str);
	}
	else
	{
		AfxMessageBox(_T("Socket连接成功"));
		WIN32_FIND_DATA FindFileData;
		CString strPathName; //定义用来保存发送文件路径的CString对象
		dlg->GetDlgItemTextW(IDC_FILEPATHNAME,strPathName);
		FindClose(FindFirstFile(strPathName,&FindFileData));
		Clientsock.Send(&FindFileData,sizeof(WIN32_FIND_DATA));
        
		CFile file;
		if(!file.Open(strPathName,CFile::modeRead|CFile::typeBinary))
		{
			AfxMessageBox(_T("文件不存在"));
			return 1;
		}

		UINT nSize = 0;
		UINT nSend = 0;

		char *szBuff=NULL;
	//发送
		while(nSize<FindFileData.nFileSizeLow)
		{
            szBuff = new char[1024];
			memset(szBuff,0x00,1024);
			nSend = file.Read(szBuff,1024);
			Clientsock.Send(szBuff,nSend);//发送数据
			nSize += nSend;
		}
		file.Close();
		delete szBuff;
		Clientsock.Close();
		(dlg->GetDlgItem(IDC_SEND))->EnableWindow(TRUE);
		AfxMessageBox(_T("文件发送成功"));
		dlg->SetDlgItemTextW(IDC_FILEPATHNAME,_T(""));
	}
	return 0;
}


 

以及服务器端使用CSocket监听的代码:

//----------------------------监听文件的线程------------------------------
UINT Thread_Func(LPVOID lpParam)  //接收文件的线程函数
{
	CServersockDlg *dlg = (CServersockDlg *)lpParam; //获取对话框指针
    (dlg->GetDlgItem(IDC_RECVDATA))->EnableWindow(FALSE);

	if(!AfxSocketInit())
	{
		AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
	}

	CString IP;
	int port;
	GetPrivateProfileString(L"ServerConfiguration",L"IP",L"没有读取到数据!",IP.GetBuffer(100),100,L".\\configuration.ini");
	port=GetPrivateProfileInt(L"ServerConfiguration",L"port",0,L".\\configuration.ini");
    
	char errBuf[100]={0};// 临时缓存
    
	SYSTEMTIME t; //系统时间结构 

	CFile logErrorfile;
	if(!logErrorfile.Open(_T("logErrorfile.txt"),CFile::modeCreate|CFile::modeReadWrite))
	{
		return 1;
	}

	CSocket Serversock;
    CSocket Clientsock;
	//创建
	if(!Serversock.Socket())
	{
		CString str;
		str.Format(_T("Socket创建失败: %d"),GetLastError());
		AfxMessageBox(str);
	}

	BOOL bOptVal = TRUE;
	int bOptLen = sizeof(BOOL);
	Serversock.SetSockOpt(SO_REUSEADDR,(void *)&bOptVal,bOptLen,SOL_SOCKET);

	//绑定
	if(!Serversock.Bind(port))
	{
		CString str;
		str.Format(_T("Socket绑定失败: %d"),GetLastError());
		AfxMessageBox(str);
	}
    //监听 
	if(!Serversock.Listen(10))
	{
		CString str;
		str.Format(_T("Socket监听失败: %d"),GetLastError());
		AfxMessageBox(str);
	}

	GetLocalTime(&t);
	sprintf_s(errBuf,"服务器已经启动...正在等待接收文件...\r\n时间:%d年%d月%d日 %2d:%2d:%2d \r\n",t.wYear,t.wMonth,t.wDay,
		t.wHour,t.wMinute,t.wSecond);
	int len = strlen(errBuf);
	logErrorfile.Write(errBuf,len);
	AfxMessageBox(_T("启动成功等待接收文件"));
	while(1)
	{
		//AfxMessageBox(_T("服务器启动成功..."));
		if(!Serversock.Accept(Clientsock)) //等待接收 
		{
			continue;
		}
		else
		{
			WIN32_FIND_DATA FileInfo;
			Clientsock.Receive(&FileInfo,sizeof(WIN32_FIND_DATA));

			CFile file;
			file.Open(FileInfo.cFileName,CFile::modeCreate|CFile::modeWrite);
			//AfxMessageBox(FileInfo.cFileName);
			int length = sizeof(FileInfo.cFileName);
			logErrorfile.Write(FileInfo.cFileName,length);
			//Receive文件的数据

			UINT nSize = 0;
			UINT nData = 0;

			char *szBuff=NULL;

			while(nSize<FileInfo.nFileSizeLow)
			{
				szBuff = new char[1024];
				memset(szBuff,0x00,1024);
				nData=Clientsock.Receive(szBuff,1024);
			    file.Write(szBuff,nData);
				nSize+=nData;
			}

			delete szBuff;
			Serversock.Close();
			Clientsock.Close();
			file.Close();
			(dlg->GetDlgItem(IDC_RECVDATA))->EnableWindow(TRUE);
			sprintf_s(errBuf,"文件接收成功...\r\n时间:%d年%d月%d日 %2d:%2d:%2d \r\n",t.wYear,t.wMonth,t.wDay,
		t.wHour,t.wMinute,t.wSecond);
			int len = strlen(errBuf);
			logErrorfile.Write(errBuf,len);
			//AfxMessageBox(_T("文件接收成功..."));
		    break;
		}
	}
	return 0;
}


 

 

本文转载自:http://blog.csdn.net/leixiaohua1020/article/details/12025731

雷霄骅

雷霄骅

粉丝 212
博文 419
码字总数 2129
作品 4
朝阳
程序员
私信 提问
有了WCF,Socket是否已人老珠黄?

1. Socket相关背景   Socket,中文译为“套接字”,最早在UNIX中引入并得到广泛应用,后来微软在设计Windows时引入了UNIX中的这个概念和相应的设计理念,并针对Windows的特性略作调整,形成...

付翔
2013/01/05
0
0
Windows Socket套接字:MFC套接字编程

网络名词解释 同步:指发送方发出数据后,等收到接收方发回的响应,才发下一个数据包的通信方式 异步:指的是发送方不等接收方响应,便接着发下个数据包的通信方式; 阻塞:指调用某函数时,...

LoSingSang
2018/04/25
270
0
Java核心(五)深入理解BIO、NIO、AIO

导读:本文你将获取到:同/异步 + 阻/非阻塞的性能区别;BIO、NIO、AIO 的区别;理解和实现 NIO 操作 Socket 时的多路复用;同时掌握 IO 最底层最核心的操作技巧。 BIO、NIO、AIO 的区别是什...

王磊的博客
2018/12/03
3.3K
0
socket 通讯开发包--Simple Sockets

Simple Sockets 是一个跨平台的 socket 通讯开发包,该工具包支持各种协议,包括 TCP、UDP、HTTP socket 等。包括阻塞和非阻塞的 sockets 、polling、线程安全和信号安全等特性。 在 Window...

匿名
2009/12/02
1.1W
0
自己写了一个socket通信服务器,服务器可以收到客户端的数据,但无法向客户端发送数据,单步执行到SendMsg时停在return -1,发送错误

基于对话框的函数为 // ServerSoDlg.cpp : 实现文件 // #include "stdafx.h" #include "ServerSo.h" #include "ServerSoDlg.h" #include "ServerSocket.h" #include "afxdialogex.h" #ifdef ......

玻璃花的秋天
2016/09/29
465
3

没有更多内容

加载失败,请刷新页面

加载更多

每天AC系列(一):三数之和

1 题目 LeetCode第15题,难度中等,题目描述: 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 注意:答...

Blueeeeeee
今天
106
0
OSChina 周四乱弹 —— 水果你们都没吃全

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @ 莱布妮子:分享五月天的单曲《温柔》@小小编辑 @cIouddyy @clouddyy 《温柔》- 五月天 手机党少年们想听歌,请使劲儿戳(这里) @FalconChe...

小小编辑
今天
237
2
聚合支付网站被黑客攻击 导致数据库被篡改的防御办法

2020春节即将来临,收到新聚合支付平台网站客户的求助电话给我们Sinesafe,反映支付订单状态被修改由原先未支付修改为已支付,导致商户那边直接发货给此订单会员了,商户和平台的损失较大,很多码...

网站安全
昨天
108
0
MySQL-基于SELECT查询的UPDATE查询

我需要检查(从同一张表)基于日期时间的两个事件之间是否存在关联。 一组数据将包含某些事件的结束日期时间,另一组数据将包含其他事件的开始日期时间。 如果第一个事件在第二个事件之前完成...

javail
昨天
90
0
将PostgreSQL数据库复制到另一台服务器

我正在将生产PostgreSQL数据库复制到开发服务器。 什么是最快,最简单的方法? #1楼 pg_dump the_db_name > the_backup.sql 然后将备份复制到您的开发服务器,并使用以下命令进行还原: ps...

技术盛宴
昨天
154
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部