c+++网络文件传输
- 格式:doc
- 大小:352.00 KB
- 文档页数:23
课程设计:FTP的设计与实现一、目的Internet提供了很多类型的网络服务,这些服务实际上都是应用层的服务。
FTP服务是基于TCP协议的网络服务。
文件传送是各种计算机网络都实现的基本功能,文件传送协议是一种最基本的应用层协议。
通过完成一个文件传送协议FTP的实现,学会利用已有网络环境设计并实现简单应用层协议,掌握TCP/IP网络应用程序基本的设计方法和实现技巧。
二、内容和要求每两人一组,分别实现FTP协议客户端程序和服务器程序。
客户端程序具有文件列表、下载文件、上传文件等常用功能。
服务器程序支持改变工作目录、文件列表、下载文件等常用的服务。
因为FTP协议比较复杂,为了简单起见,客户端只实现FTP客户端协议的一个子集,总的来说有以下几个功能:●连接到指定的FTP服务器;●断开和主机的连接;●进入子目录;●退出子目录;●列出服务器当前目录下的所有文件●从服务器下载指定的文件到本地(可以同时指定多个文件连续下载)●从本地上传指定的文件到服务器实现以上几个功能时会涉及到下面的几个FTP命令:●USER username●PASS password●CWD directory-name●PORT host-port●TYPE A or I●RETR filename●STOR filename●LIST directory用户界面应该能够为程序输入下面的信息:●服务器主机名●用户名、口令●数据的传送类型●要进入的服务器目录●要下载的远程文件名●要上载的本地文件名和远程文件名同时,界面也为用户输出以下的信息:●FTP服务器上的文件和目录列表●从服务器返回的应答使用Socket进行Client/Server程序设计的一般连接过程是这样的:Server端Listen(监听)某个端口是否有连接请求,Client端向Server端发出Connect(连接)请求,Server端向Client端发回Accept(接受)消息。
【背景】最近做了一个双机备份,就是服务器上有个文件夹,会接收客户端传来的文件,而我们要做的就是同步这台服务器和另一台备用服务器上的文件.为了实现这个功能我们使用的tcp点对点传输.【开发环境】VS2005【实现原理】要实现同步要解决两个问题,一个是获取本地服务器上上传上来的文件,二是实现两台机器间的文件传输.第一个问题我们用的FileSystemWatcher这个可以监视指定文件夹下的文件变动,然后我们把变动的文件信息记录到数据库,在指定的时间间隔后同步两台机器的文件.第二个问题我们用的tcp文件传输,我们按照一定的原则通过传输消息来告知备份服务器的要传输的文件名称和大小,然后传输文件.【代码】1:FileSystemWatcher监视文件变动的就不介绍了,很简单的winform控件应用. 2:为了完成文件传输,我做了一个TcpHelper类库,其中包括TcpCommon,TcpClientHelper,TcpListenerHelper三个类,TcpCommon主要实现了文件传输时用的一些公共的方法比如发送接收文件,发送接收消息,和文件hash的计算TcpCommonusing System;using System.Collections.Generic;using System.Text;using System.Security.Cryptography;using System.IO;using .Sockets;namespace Xpwy.Backup.PTcpHelper{internal class TcpCommon{private static readonly int _blockLength = 500 * 1024;///<summary>///计算文件的hash值///</summary>internal string CalcFileHash(string FilePath){MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvid er();byte[] hash;using (FileStream fs = new FileStream(FilePath, FileMode. Open, FileAccess.Read, FileShare.Read, 4096)){hash = puteHash(fs);}return BitConverter.ToString(hash);}///<summary>///发送文件///</summary>///<param name="filePath"></param>///<param name="stream"></param>///<returns></returns>internal bool SendFile(string filePath, NetworkStream stream) {FileStream fs = File.Open(filePath, FileMode.Open);int readLength = 0;byte[] data = new byte[_blockLength];//发送大小byte[] length = new byte[8];BitConverter.GetBytes(new FileInfo(filePath).Length).Copy To(length, 0);stream.Write(length, 0, 8);//发送文件while ((readLength = fs.Read(data, 0, _blockLength)) > 0) {stream.Write(data, 0, readLength);}fs.Close();return true;}///<summary>///接收文件///</summary>///<param name="filePath"></param>///<param name="stream"></param>///<returns></returns>internal bool ReceiveFile(string filePath, NetworkStream stre am){try{long count = GetSize(stream);if (count == 0){return false;}long index = 0;byte[] clientData = new byte[_blockLength];if (File.Exists(filePath)){File.Delete(filePath);}string path=new FileInfo(filePath).Directory.FullName;if (!Directory.Exists(path)){Directory.CreateDirectory(path);}FileStream fs = File.Open(filePath, FileMode.OpenOrCr eate);try{//计算当前要读取的块的大小int currentBlockLength = 0;if (_blockLength < count - index){currentBlockLength = _blockLength;}else{currentBlockLength =(int)( count - index);}int receivedBytesLen = stream.Read(clientData, 0, currentBlockLength);index += receivedBytesLen;fs.Write(clientData, 0, receivedBytesLen);while (receivedBytesLen > 0 && index < count){clientData = new byte[_blockLength];receivedBytesLen = 0;if (_blockLength < count - index){currentBlockLength = _blockLength;}else{currentBlockLength = (int)(count - index); }receivedBytesLen = stream.Read(clientData, 0, currentBlockLength);index += receivedBytesLen;fs.Write(clientData, 0, receivedBytesLen);}}catch (Exception ex){return false;}finally{fs.Close();}}catch (Exception ex){return false;}return true;}///<summary>///发送消息///</summary>///<param name="message"></param>///<param name="stream"></param>///<returns></returns>internal bool SendMessage(string message, NetworkStream strea m){byte[] data = Encoding.UTF8.GetBytes(message);byte[] resultData = new byte[8 + data.Length];BitConverter.GetBytes(data.Length).CopyTo(resultData, 0);data.CopyTo(resultData, 8);stream.Write(resultData, 0, resultData.Length);return true;}///<summary>///读取消息///</summary>///<param name="stream"></param>///<returns></returns>internal string ReadMessage(NetworkStream stream){string result = "";int messageLength = 0;byte[] resultbyte = new byte[500 * 1024];//读取数据大小int index = 0;int count = GetSize(stream);byte[] data = new byte[count];while (index < count && (messageLength = stream.Read(dat a, 0, count - index)) != 0){data.CopyTo(resultbyte, index);index += messageLength;}result = Encoding.UTF8.GetString(resultbyte, 0, index);return result;}///<summary>///获取要读取的数据的大小///</summary>///<param name="stream"></param>///<returns></returns>private int GetSize(NetworkStream stream){int count = 0;byte[] countBytes = new byte[8];try{if (stream.Read(countBytes, 0, 8) == 8){count = BitConverter.ToInt32(countBytes, 0);}else{return0;}}catch (Exception ex){}return count;}}}TcpClientHelperusing System;using System.Collections.Generic;using System.Text;using .Sockets;namespace Xpwy.Backup.PTcpHelper{public class TcpClientHelper:IDisposable{TcpClient client;NetworkStream netstream;string _serverip = "127.0.0.1";int _port = 8080;TcpCommon tcpCommon = new TcpCommon();#region TcpClientHelper constructorpublic TcpClientHelper(string strServerIP, int serverPort) {_serverip = strServerIP;_port = serverPort;}#endregionpublic void Start(){client = new TcpClient(_serverip, _port);netstream = client.GetStream();}public void Stop(){if (netstream != null){netstream.Close();}if (client != null){client.Close();}}#region TcpCommon所有方法public string CalcFileHash(string FilePath){return tcpCommon.CalcFileHash(FilePath);}public bool SendFile(string filePath){return tcpCommon.SendFile(filePath, netstream);}public bool ReceiveFile(string filePath){return tcpCommon.ReceiveFile(filePath, netstream); }public bool SendMessage(string message){return tcpCommon.SendMessage(message, netstream); }public string ReadMessage(){return tcpCommon.ReadMessage(netstream); }#endregion#region IDisposable 成员public void Dispose(){if (netstream != null){netstream.Close();}if (client != null){client.Close();}}#endregion}}TcpListenerHelperusing System;using System.Collections.Generic;using System.Text;using .Sockets;using ;using System.Threading;namespace Xpwy.Backup.PTcpHelper{public class TcpListenerHelper{private string _strServerIP = "";private int _serverPort = 0;TcpListener server;TcpClient client;NetworkStream netstream;IAsyncResult asyncResult;TcpCommon tcpCommon = new TcpCommon();ManualResetEvent listenConnected = new ManualResetEvent(fals e);bool _active = false;public TcpListenerHelper(string strServerIP, int serverPort) {_strServerIP = strServerIP;_serverPort = serverPort;server = new TcpListener(IPAddress.Parse(strServerIP), se rverPort);server.Server.ReceiveTimeout = 6000;server.Server.SendTimeout = 6000;}///<summary>///启动///</summary>public void Start(){try{_active = true;server.Start();}catch (Exception ex){throw ex;}}///<summary>///停止///</summary>public void Stop(){try{_active = false;if (client != null){client.Close();}if (netstream != null){netstream.Close();}server.Stop();}catch (Exception ex){throw ex;}}public void Listen(){listenConnected.Reset();asyncResult = server.BeginAcceptTcpClient(new AsyncCallba ck(AsyncCall), server);}public void AsyncCall(IAsyncResult ar){try{TcpListener tlistener = (TcpListener)ar.AsyncState;if (_active){client = tlistener.EndAcceptTcpClient(ar);netstream = client.GetStream();}else{client = null;netstream = null;}listenConnected.Set();}catch (Exception ex){throw ex;}}public bool WaitForConnect(){listenConnected.WaitOne();if (client != null && netstream != null){return true;}else{return false;}}#region TcpCommon所有方法///<summary>///计算文件的hash值///</summary>public string CalcFileHash(string FilePath){return tcpCommon.CalcFileHash(FilePath);}///<summary>///发送文件///</summary>///<param name="filePath"></param>///<returns></returns>public bool SendFile(string filePath){return tcpCommon.SendFile(filePath, netstream);}///<summary>///接收文件///</summary>///<param name="filePath"></param>///<returns></returns>public bool ReceiveFile(string filePath){return tcpCommon.ReceiveFile(filePath, netstream); }///<summary>///发送消息///</summary>///<param name="message"></param>///<returns></returns>public bool SendMessage(string message){return tcpCommon.SendMessage(message, netstream);}///<summary>///接收消息///</summary>///<returns></returns>public string ReadMessage(){return tcpCommon.ReadMessage(netstream);}#endregion#region IDisposable 成员public void Dispose(){Stop();}#endregion}}3:调用的代码server端:public void DoWork(object state){TcpListenerHelper tlistener = (TcpListenerHelper)state; tlistener.Listen();//监听while (tlistener.WaitForConnect())//等待知道监听到了连接{try{string firstMessage = "";while (!string.IsNullOrEmpty((firstMessage = tlis tener.ReadMessage()))){if (firstMessage.ToLower() == "filebak".ToLow er()){tlistener.SendMessage("filebakok");#region文件备份string filepath = bine(Environmen t.CurrentDirectory, "FileBak\\" + tlistener.ReadMessage()).ToString(); tlistener.ReceiveFile(filepath);if (tlistener.CalcFileHash(filepath) == t listener.ReadMessage()){tlistener.SendMessage("ok");}else{tlistener.SendMessage("wrong");}#endregion}else if (firstMessage.ToLower() == "DBBak".To Lower()){#region数据库备份tlistener.SendMessage("dbbakok");string filename = tlistener.ReadMessage();string filepath = bine(System.Env ironment.CurrentDirectory, "DBBak") +"\\"+ filename;//接收文件tlistener.ReceiveFile(filepath);//验证hash值string hash = tlistener.ReadMessage();if (hash == tlistener.CalcFileHash(filepa th))tlistener.SendMessage("ok");elsetlistener.SendMessage("wrong");#endregion}}catch{}tlistener.Listen();//监听下一个连接}}client端:private void FileBackup(object arg){TcpClientHelper client = (TcpClientHelper)arg;//获取需备份的文件DataTable dt = this._oFileWatch.GetBackupFiles();if (dt != null){for (int i = 0; i < dt.Rows.Count; i++){client.SendMessage("FileBak");if (client.ReadMessage().ToLower() == "filebakok") {client.SendMessage(dt.Rows[i]["RelativePath"]. ToString());client.SendFile(dt.Rows[i]["FullPath"].ToStri ng());client.SendMessage(client.CalcFileHash(dt.Row s[i]["FullPath"].ToString()));if (client.ReadMessage().ToLower() == "ok"){LOGClass.WriteLog("备份文件【" + dt.Rows[i] ["FullPath"].ToString() + "】成功");}else{LOGClass.WriteLog("备份文件【" + dt.Rows[i] ["FullPath"].ToString() + "】失败。
第ChpNum章文件传输协议的C语言实现1设计目的本设计旨在利用Winsock 简单实现FTP(File Transfer Protocol,文件传输协议)的客户端和服务器端程序。
通过完成此设计,了解Winsock API函数调用方法和一般网络应用程序的编程方法,理解FTP协议,掌握C语言设计FTP协议软件的基本技术,为将来开发其他通信协议软件打下坚实基础。
2 设计准备(1)连入同一局域网的PC,每人一台。
(2)PC装有Windows操作系统、Visual C++ 编译器及开发手册MSDN 。
3关键技术文件传输协议介绍FTP 是File Transfer Protocol(文件传输协议)的英文简称,用于Internet上的控制文件的双向传输。
在实现的层面上,FTP又可理解为一个可用于文件传输的客户机/服务器系统,该系统包括客户机端程序和服务器端程序,客户端和服务器端通信规则为FTP协议。
用户通过客户机程序向服务器程序发出命令请求,服务器程序执行用户所发出的命令,并将执行的结果返回到客户机。
比如说,用户发出一条命令,要求服务器向用户传送某一个文件的一份拷贝,服务器会响应这条命令,将指定文件送至用户的机器上。
客户机程序接收到这个文件,将其存放在用户目录中。
在通信协议的分层模型中,文件传输协议是在TCP(Transmission control Protocol,传输控制协议)之上的一个应用层协议,应用程序之间的通信需要用到传输层提供的字节流透明无误传输服务。
Windows操作系统具有TCP/IP协议栈,应用程序可通过Winsock API函数的调用实现端到端透明数据链接的建立。
Winsock API介绍因特网(Internet)最初是基于Unix的,而Sockets(套接字)是Unix第一个支持TCP/IP 协议栈的网络API,最早于1982年8月随BSD版Unix推出,常被称为Berkeley sockets (伯克利套接字)。
c++实现文件传输之一:框架结构和界面实现在木马中文件管理的重要性,是无需质疑的,对于文件的管理,做到并不难,但做好却也不易在我们编写一个功能完整的“文件木马”其实现效果如图所示。
为了文章的完整性,我们将分为数篇来介绍,本文主要介绍程序的整体框架和界面实现,在以后的文章中将以此框架为基础实现详细的功能。
实现:枚举磁盘,枚举目录,获取文件信息上传文件,下载文件,执行文件,创建目录,删除目录等传输控制结构要实现客户端与服务端的通信,设计一个合理的传输控制结构,会使后面的工作轻松很多,为了使代码易读首先对要使用的命令进行预定义其各个命令定义如下#define GetDriver 0x01 //磁盘信息#define GetDirInfo 0x02 //目录信息#define ExecFile 0x03 //执行文件#define GetFile 0x04 //下载文件#define PutFile 0x05 //上传文件#define DelFile 0x06 //删除文件#define DelDir 0x07 //删除目录#define CreateDir 0x08 //创建目录#define FileInfo 0x09 //文件信息#define GetScreen 0x10 //查看屏幕在程序的网络通信中主要有操作命令 ,命令对像,和具体数据三部分,对于命令的传输定义如下结构typedef struct{int ID; //操作命令BYTE lparam[BUF_LEN*2]; //命令对像}COMMAND;因为在程序中打交道最多的就是文件,对文件的详细属性定义如下结构typedef struct{char FileName[MAX_PATH]; //文件名称int FileLen; //文件长度char Time[50]; //时间信息BOOL IsDir; //为目录否BOOL Error; //错误信息HICON hIcon; //图标句柄}FILEINFO;服务端结构服务端还是比较简单的其整体思路如下1.服务端循环接受连接,并把连接交给线程处理2.线程接受"命令数据",并跟据命令ID将命令对像和SOCKET句柄传给处理函数3.函数执行指定功能,并返回执行结果对整体结构的描述,我们用伪代码表述如下main(){ /*初示化设置......*/while(true){if(client=accept(server,(sockaddr *)&clientaddr,&len))//循环接受连接{CreateThread(NULL,NULL,SLisen,(LPVOID)client,NULL,NULL);//传递线程处理}}/*清理释放资源......*/WSACleanup();}服务端程序运行后循环接受连接,如果有新的连接就传递给新的线程处理,线程代码如下DWORD WINAPI SLisen(LPVOID lparam){SOCKET client=(SOCKET)lparam;COMMAND command;while(1){if(recv(client,(char*)&command,sizeof(command),0)==SOCKET_ERROR)//接受命令数据{cout<<"The Clinet Socket is Closed/n";break;}else{switch(command.ID)//判断命令ID{case GetDriver://将命令对像和SOCKET句柄传递给处理函数GetDriverProc (command,client);break;case DelFile:DelFileProc (command,client);break;/*其它命令......*/}}}}线程式的功能是接受客户端的"命令数据",并跟跟据命令ID 将命令对像传递给处理函数,由函数完成指定的功能以删除文件命令为例其函数格式如下DWORD DelFileProc (COMMAND command,SOCKET client){if(DeleteFile((char*)command.lparam)==0)//command.lparam为命令对像,这里为要删除的文件路径{send(client,"删除失败...");}else{send(client,"删除成功...");}}很容易看出,处理函数接受"命令对像"和客户端SOCKET句柄,执行后会把结果传递回去....客户端结构客户端结构的实现思路如下1.跟服务端建立连接2.发送用户命令3.启动一个线程,用于接受服务端的返回信息对整体结构的描述,我们用伪代码表述如下void CMyDlg::OnConnect(){if(connect(server,(SOCKADDR*)&serveraddr,sizeof(serveraddr))<0)//连接....{return ;}CreateThread(NULL,NULL,CLisen,this,NULL,NULL);//创建线程用于接受SERVER返回信息}对于用户发送的命令我们仍以删除文件为例说明其代码如下void CMyDlg::OnMenuDelFile(){HTREEITEM CurrentNode = m_tree.GetSelectedItem(); //取得选择的节点CString FullPath =GetFullPath(CurrentNode); //取得节点全目录COMMAND command;command.ID=DelFile; //设置命令为删除文件 //删除文件command.lparam=FullPath.LockBuffer()); //将路径加入命令对像send(server,command);}用于接受SERVER返回信息的线程,和服务端接受命令线程相似,这里就不再说明了,有兴趣可以看下源代码到这里程序的流程框架就介绍完了,下面我们再看一下程序的界面设置.界面实现程序的主界面如上图所示,主程序是一个对话框,主要包括一个树控件m_tree 和列表控件m_list分别用于显示磁盘目录和文件,在对话框初示化时用以下代码设置树控件的属性DWORD dwStyle = GetWindowLong(m_tree.m_hWnd,GWL_STYLE);dwStyle |=TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT; SetWindowLong(m_tree.m_hWnd,GWL_STYLE,dwStyle);对于列表框控件则没有太多要求,要留意的是,如果显示图标应该把Styles显示属性设置为ICONVC的做出的界面,常常让人有种摔键盘的冲动。
c++文件传输毕业设计摘要:本文描述了一个基于C++的文件传输系统的设计与实现。
该系统具有高效和安全的特点,并且采用了TCP/IP协议进行数据传输。
系统分为客户端和服务器端,客户端可以将本地文件传输到服务器端,服务器端可以接收并保存文件。
在设计过程中,使用了文件流、套接字编程和多线程技术。
通过对系统进行测试和评估,验证了其稳定性和可靠性。
最终结果表明,该文件传输系统能够快速、安全地传输大文件,并且能够满足用户的需求。
1. 引言文件传输是计算机网络中常见的任务之一。
随着互联网的发展和普及,文件传输系统需要具备高效、安全、稳定和可靠等特点。
本文设计了一个基于C++的文件传输系统,该系统通过TCP/IP协议进行数据传输,能够满足用户的需求。
2. 系统设计2.1 系统结构文件传输系统分为客户端和服务器端两部分。
客户端提供了文件选择和传输功能,服务器端则负责接收和保存文件。
2.2 数据传输系统基于TCP/IP协议进行数据传输,使用套接字编程进行通信。
客户端通过套接字将文件内容划分为较小的数据块并发送给服务器端,服务器端再将接收到的数据块组合成完整的文件。
2.3 多线程技术为了提高系统的传输效率,使用了多线程技术。
客户端和服务器端均开启多个线程进行文件传输,从而实现并发传输。
3. 系统实现3.1 客户端实现客户端使用C++编写,通过用户界面提供文件选择的功能。
客户端接收用户选择的文件,并将文件内容划分为数据块进行传输。
客户端还可显示传输进度和传输结果。
3.2 服务器端实现服务器端使用C++编写,通过套接字接收客户端传输的数据块。
服务器端将接收到的数据块组合成完整的文件,并保存到本地磁盘中。
服务器端还可显示传输进度和传输结果。
4. 系统测试与评估为了验证系统的稳定性和可靠性,对系统进行了测试。
通过传输大文件和多个文件,评估系统的传输速度和传输成功率。
测试结果表明,系统能够快速、安全地传输大文件,并且具有良好的稳定性和可靠性。
////////////////////////////////////#include <netinet/in.h> // for sockaddr_in#include <sys/types.h> // for socket#include <sys/socket.h> // for socket#include <stdio.h> // for printf#include <stdlib.h> // for exit#include <string.h> // for bzero#include <time.h> //for time_t and time#define HELLO_WORLD_SERVER_PORT 7754#define LENGTH_OF_LISTEN_QUEUE 20#define BUFFER_SIZE 1024int main(int argc, char **argv){struct sockaddr_in server_addr;bzero(&server_addr,sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = htons(INADDR_ANY);server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);// time_t now;FILE *stream;int server_socket = socket(AF_INET,SOCK_STREAM,0);if( server_socket < 0){printf("Create Socket Failed!");exit(1);}if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr))) {printf("Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT); exit(1);}if ( listen(server_socket, LENGTH_OF_LISTEN_QUEUE) ){printf("Server Listen Failed!");}while (1)struct sockaddr_in client_addr;socklen_t length = sizeof(client_addr);int new_server_socket = accept(server_socket,(struct sockaddr*)&client_addr,&length); if ( new_server_socket < 0){printf("Server Accept Failed!\n");break;}char buffer[BUFFER_SIZE];bzero(buffer, BUFFER_SIZE);strcpy(buffer,"Hello,World! ");strcat(buffer,"\n"); //send(new_server_socket,buffer,BUFFER_SIZE,0);bzero(buffer,BUFFER_SIZE);= recv(new_server_socket,buffer,BUFFER_SIZE,0);if (length < 0){printf("Server Recieve Data Failed!\n");exit(1);}printf("\n%s",buffer);if((stream = fopen("z.mp3","r"))==NULL){printf("The file 'data1' was not opened! \n");exit(1);}elseprintf("The file 'filename' was opened! \n");bzero(buffer,BUFFER_SIZE);int lengsize = 0;while((lengsize = fread(buffer,1,1024,stream)) > 0){printf("lengsize = %d\n",lengsize);if(send(new_server_socket,buffer,lengsize,0)<0){printf("Send File is Failed\n");break;}bzero(buffer, BUFFER_SIZE);}if(fclose(stream))printf("The file 'data' was not closed! \n");exit(1);close(new_server_socket);}close(server_socket);return 0;}//client.c////////////////////////////////////#include <netinet/in.h> // for sockaddr_in#include <sys/types.h> // for socket#include <sys/socket.h> // for socket#include <stdio.h> // for printf#include <stdlib.h> // for exit#include <string.h> // for bzero#include <time.h> //for time_t and time #include <arpa/inet.h>#define HELLO_WORLD_SERVER_PORT 7754#define BUFFER_SIZE 1024int main(int argc, char **argv){if (argc != 2){printf("Usage: ./%s ServerIPAddress\n",argv[0]);exit(1);}//time_t now;FILE *stream;struct sockaddr_in client_addr;bzero(&client_addr,sizeof(client_addr));client_addr.sin_family = AF_INET;client_addr.sin_addr.s_addr = htons(INADDR_ANY);client_addr.sin_port = htons(0);int client_socket = socket(AF_INET,SOCK_STREAM,0);if( client_socket < 0){printf("Create Socket Failed!\n");exit(1);}if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr))){printf("Client Bind Port Failed!\n");exit(1);}struct sockaddr_in server_addr;bzero(&server_addr,sizeof(server_addr));server_addr.sin_family = AF_INET;if(inet_aton(argv[1],&server_addr.sin_addr) == 0){printf("Server IP Address Error!\n");exit(1);}server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);socklen_t server_addr_length = sizeof(server_addr);if(connect(client_socket,(struct sockaddr*)&server_addr, server_addr_length) < 0) {printf("Can Not Connect To %s!\n",argv[1]);exit(1);}char buffer[BUFFER_SIZE];bzero(buffer,BUFFER_SIZE);int length = recv(client_socket,buffer,BUFFER_SIZE,0);if(length < 0){printf("Recieve Data From Server %s Failed!\n", argv[1]); exit(1);}printf("\n%s\n",buffer);bzero(buffer,BUFFER_SIZE);bzero(buffer,BUFFER_SIZE);strcpy(buffer,"Hello, World! From Client\n");send(client_socket,buffer,BUFFER_SIZE,0);if((stream = fopen("data","w+t"))==NULL){printf("The file 'data' was not opened! \n");}elsebzero(buffer,BUFFER_SIZE);length = 0;while( length = recv(client_socket,buffer,BUFFER_SIZE,0)) {if(length < 0){printf("Recieve Data From Server %s Failed!\n", argv[1]); break;}int write_length = fwrite(buffer,sizeof(char),length,stream); if (write_length<length){printf("File is Write Failed\n");break;}bzero(buffer,BUFFER_SIZE);}printf("Recieve File From Server[%s] Finished\n", argv[1]); fclose(stream);close(client_socket);return 0;}。
网络通信一般都是通过Socket进行的,称为进程通信机制,通常也称作"套接字",用于描述ip地址和端口,是一个通信链的句柄。
先学习一下socket基本原理:socket原理:在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务。
每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。
Socket 正如其英文原意那样,象一个多孔插座。
一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电,有的提供110伏交流电,有的则提供有线电视节目。
客户软件将插头插到不同编号的插座,就可以得到不同的服务。
Socket的形像理解:socket非常类似于电话插座。
以一个国家级电话网为例。
电话的通话双方相当于相互通信的2个进程,区号是它的网络地址;区内一个单位的交换机相当于一台主机,主机分配给每个用户的局内号码相当于socket号。
任何用户在通话之前,首先要占有一部电话机,相当于申请一个socket;同时要知道对方的号码,相当于对方有一个固定的socket。
然后向对方拨号呼叫,相当于发出连接请求(假如对方不在同一区内,还要拨对方区号,相当于给出网络地址)。
对方假如在场并空闲(相当于通信的另一主机开机且可以接受连接请求),拿起电话话筒,双方就可以正式通话,相当于连接成功。
双方通话的过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。
通话结束后,一方挂起电话机相当于关闭socket,撤消连接。
Socket 通信应用示图TCP/IP 客户端/服务端通信流程图通过Socket通信原理的认识,下面可以开始写一个简单的通信程序,进行验证。
在这里,做了一个局域网内文件传输程序,其实模仿飞鸽传输的功能。
在公司里面是禁用QQ,不能使用QQ,有时发现挺麻烦的,传输文件不方便,搞得经常要用U盘来拷东西。
C语言实现UDP网络传输UDP(User Datagram Protocol,用户数据报协议)是一种面向无连接的传输协议,它在网络编程中具有重要的作用。
本文将介绍C语言如何实现UDP网络传输的基本原理和步骤。
一、UDP网络传输简介UDP是一种简单的传输层协议,相对于TCP(Transmission Control Protocol,传输控制协议)来说,UDP更加轻量级。
它不提供可靠性和流量控制,但是具有实时性较高的特点,适用于需要快速传输数据的场景,如音频、视频等实时应用。
UDP协议的数据包格式主要包括源端口号、目标端口号、长度、校验和以及数据。
由于UDP是无连接的,所以每个数据包都是独立发送的,不需要建立和维护连接,这使得UDP的实现相对简单。
二、C语言实现UDP网络传输步骤要使用C语言实现UDP网络传输,我们需要按照以下步骤进行操作:1. 创建套接字(Socket)在C语言中,使用socket()函数创建一个套接字,该套接字用于后续的数据传输。
在创建套接字时,需要指定协议簇(AF_INET代表IPv4)和套接字类型(SOCK_DGRAM代表使用UDP协议)。
2. 绑定本地地址和端口号使用bind()函数将套接字与本地地址和端口号绑定,以便接收数据和发送数据。
通常将本地地址设置为INADDR_ANY,端口号可以自定义。
3. 接收数据使用recvfrom()函数接收远程主机发送的数据,该函数会将接收到的数据存储到指定的缓冲区中,并返回接收到的字节数。
可以通过指定发送方的地址和端口号来实现数据的精确接收。
4. 发送数据使用sendto()函数将数据发送给目标主机,该函数需要指定目标主机的地址和端口号,并将待发送的数据和数据长度作为参数传入。
5. 关闭套接字使用close()函数关闭套接字,释放资源。
三、C语言实现UDP网络传输示例代码```c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <arpa/inet.h>#define MAX_BUFFER_SIZE 1024#define SERVER_PORT 8888#define SERVER_IP "127.0.0.1"int main() {int sockfd;char buffer[MAX_BUFFER_SIZE];struct sockaddr_in server_addr, client_addr;socklen_t client_len = sizeof(client_addr);// 创建套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("Error in creating socket");exit(1);}memset(&server_addr, 0, sizeof(server_addr));memset(&client_addr, 0, sizeof(client_addr));// 设置服务器地址和端口号server_addr.sin_family = AF_INET;server_addr.sin_port = htons(SERVER_PORT);server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);// 绑定本地地址和端口号if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("Error in binding");exit(1);}printf("Server is listening for incoming connections...\n");while (1) {// 接收数据memset(buffer, 0, sizeof(buffer));ssize_t recv_len = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &client_len);if (recv_len < 0) {perror("Error in receiving data");exit(1);}printf("Received data from client: %s\n", buffer);// 发送数据const char* msg = "Hello, client!";ssize_t send_len = sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)&client_addr, client_len);if (send_len != strlen(msg)) {perror("Error in sending data");exit(1);}printf("Sent response to client: %s\n", msg);}// 关闭套接字close(sockfd);return 0;}```以上是一个简单的UDP服务器示例代码,它通过创建套接字、绑定地址和端口、接收数据并发送响应的方式来实现UDP网络传输。
使用C#进行点对点通讯和文件传输程序分三部分,包括发送部分、接受部分和一个两者共享的通讯基类,这个基类才是俺心血的结晶:)一、通讯基类using System;using .Sockets;using ;using System.IO ;using System.Windows.Forms;using System.Text;namespace BaseClass{/// 传送信息的格式为给定长度的命令部分+给定长度的命令注释部分+可变长度的长度信息+可变长度的信息部分public class CommunClass{public CommunClass(){// TODO: 在此处添加构造函数逻辑}/// 命令部分的长度private static readonly int CMDLEN = 50 ;/// 命令注释部分的长度private static readonly int DESCLEN = 100 ;/// 可变长度的长度信息部分所占的字节数private static readonly int DYNAMICLENGTHLEN = 10 ;/// 每次处理可变信息部分的长度private static readonly int DEALLEN = 1024 ;/// /应答的最大长度private static readonly int RESPONLEN = 20 ;/// 用于填充命令或注释不足长度部分的字符private static readonly char FILLCHAR = ''^'' ;/// 成功发送一部分数据后的回调方法(也可以认为是触发的事件,但严格来说还不是)public delegate void OnSend(int iTotal,int iSending) ;/// 根据给定的服务器和端口号建立连接/// 服务器名/// 端口号public static Socket ConnectToServer(string strHost,int iPort){try{IPAddress ipAddress = Dns.Resolve(strHost).AddressList[0];IPEndPoint ipPoint = new IPEndPoint(ipAddress,iPort) ;Socket s = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp) ;s.Connect(ipPoint) ;return s ;}catch (Exception e){ throw (new Exception("建立到服务器的连接出错" + e.Message)) ; }}/// 将文本写到Socket中/// 要发送信息的Socket/// 要发送的信息/// 是否成功public static bool WriteTextToSocket(Socket s,string strInfo){byte [] buf = Encoding.UTF8.GetBytes(strInfo) ;try { s.Send(buf,0,buf.Length,SocketFlags.None) ; return true ; }catch(Exception err) { MessageBox.Show("发送文本失败!"+err.Message) ; return false ; } }/// 将命令文本写到Socket中/// 要发送命令文本的Socket/// 要发送的命令文本// 是否成功public static bool WriteCommandToSocket(Socket s,string strCmd){if (strCmd == "")strCmd = "NOP" ;strCmd = strCmd.PadRight(CMDLEN,FILLCHAR) ;return WriteTextToSocket(s,strCmd) ;}////// 将命令注释写到Socket中////// 要发送命令注释的Socket/// 要发送的命令注释/// 是否成功public static bool WriteCommandDescToSocket(Socket s,string strDesc){if (strDesc == "")strDesc = "0" ;strDesc = strDesc.PadRight(DESCLEN,FILLCHAR) ;return WriteTextToSocket(s,strDesc) ;}/// 发送可变信息的字节数/// 要发送字节数的Socket/// 字节数/// 是否成功public static bool WriteDynamicLenToSocket(Socket s,int iLen){string strLen = iLen.ToString().PadRight(DYNAMICLENGTHLEN,FILLCHAR) ;return WriteTextToSocket(s,strLen) ;}/// 将缓存的指定部分发送到Socket/// 要发送缓存的Socket/// 要发送的缓存/// 要发送缓存的起始位置/// 要发送缓存的字节数/// 每次发送的字节说/// 每次发送成功后的回调函数/// 是否发送成功public static bool WriteBufToSocket(Socket s,byte [] buf,int iStart,int iCount,int iBlock,OnSend SendSuccess) {int iSended = 0 ;int iSending = 0 ;while(iSended{if (iSended + iBlockiSending = iBlock ;elseiSending = iCount - iSended ;s.Send(buf,iStart+iSended,iSending,SocketFlags.None) ;iSended += iSending ;if (ReadResponsionFromSocket(s)=="OK")if (SendSuccess != null)SendSuccess(iCount,iSended) ;elsereturn false;}return true ;}/// 将长度不固定文本发送到socket/// 要发送文本的Socket/// 要发送的文本/// 成功发送一部分文本后的回调函数/// 得到文本长度的回调函数public static bool WriteDynamicTextToSocket(Socket s,string strText, OnSend OnSendText){byte [] buf = Encoding.UTF8.GetBytes(strText) ;int iLen = buf.Length ;try{WriteDynamicLenToSocket(s,iLen) ;return WriteBufToSocket(s,buf,0,iLen,DEALLEN,OnSendText) ;}catch(Exception err){MessageBox.Show("发送文本失败!"+err.Message) ;return false ;}}/// 将文件写到Socket/// 要发送文件的Socket/// 要发送的文件/// 是否成功public static bool WriteFileToSocket(Socket s,string strFile,OnSend OnSendFile){FileStream fs = new FileStream(strFile,FileMode.Open,FileAccess.Read,FileShare.Read) ; int iLen = (int)fs.Length ;WriteDynamicLenToSocket(s,iLen) ;byte [] buf = new byte[iLen] ;try{fs.Read(buf,0,iLen) ;return WriteBufToSocket(s,buf,0,iLen,DEALLEN,OnSendFile) ;}catch(Exception err){MessageBox.Show("发送文件失败!"+err.Message) ;return false ; }finally { fs.Close() ; }}/// 对方对自己消息的简单回应public static string ReadResponsionFromSocket( Socket s){byte [] bufCmd = new byte[RESPONLEN] ;int iCount = s.Receive(bufCmd) ;string strRespon = Encoding.UTF8.GetString(bufCmd,0,iCount) ;return strRespon ;}/// 从Socket读取命令/// 要读取命令的Socket/// 读取的命令public static string ReadCommandFromSocket( Socket s){byte [] bufCmd = new byte[CMDLEN] ;int iCount = s.Receive(bufCmd,0,CMDLEN,SocketFlags.Partial) ;string strCommand = Encoding.UTF8.GetString(bufCmd,0,CMDLEN) ;return strCommand = strCommand.TrimEnd(FILLCHAR) ;}/// 读取命令注释/// 要读取命令注释的Socket/// 读取的命令注释public static string ReadCommandDescFromSocket( Socket s){byte [] bufCmd = new byte[DESCLEN] ;int iCount = s.Receive(bufCmd,0,DESCLEN,SocketFlags.Partial) ;string strCommand = Encoding.UTF8.GetString(bufCmd,0,DESCLEN) ;return strCommand = strCommand.TrimEnd(FILLCHAR) ;}/// 读取可变部分的长度// 要读取可变部分长度的Socket/// 读取的可变部分的长度public static int ReadDynamicLenFromSocket( Socket s){byte [] bufCmd = new byte[DYNAMICLENGTHLEN] ;int iCount = s.Receive(bufCmd,0,DYNAMICLENGTHLEN,SocketFlags.Partial) ; string strCommand = Encoding.UTF8.GetString(bufCmd,0,DYNAMICLENGTHLEN) ; return int.Parse(strCommand.TrimEnd(FILLCHAR)) ;}/// 读取文本形式的可变信息/// 要读取可变信息的Socket/// 读取的可变信息public static string ReadDynamicTextFromSocket( Socket s){int iLen = ReadDynamicLenFromSocket(s) ;byte [] buf = new byte[iLen] ;string strInfo = "" ;int iReceiveded = 0 ;int iReceiveing = 0 ;while(iReceiveded{if (iReceiveded + DEALLENiReceiveing = DEALLEN ;elseiReceiveing = iLen - iReceiveded ;s.Receive(buf,iReceiveded,iReceiveing,SocketFlags.None) ;CommunClass.WriteTextToSocket(s,"OK") ;iReceiveded+= iReceiveing ;}strInfo = Encoding.UTF8.GetString(buf,0,iLen) ;return strInfo ;}////// 读取文件形式的可变信息////// 要读取可变信息的Socket/// 读出后的文件保存位置/// 是否读取成功public static bool ReadDynamicFileFromSocket( Socket s,string strFile){int iLen = ReadDynamicLenFromSocket(s) ;byte [] buf = new byte[iLen] ;FileStream fs = new FileStream(strFile,FileMode.Create,FileAccess.Write) ;try{int iReceiveded = 0 ;int iReceiveing = 0 ;while(iReceiveded{if (iReceiveded + DEALLENiReceiveing = DEALLEN ;elseiReceiveing = iLen - iReceiveded ;s.Receive(buf,iReceiveded,iReceiveing,SocketFlags.None) ;CommunClass.WriteTextToSocket(s,"OK") ;iReceiveded+= iReceiveing ;}fs.Write(buf,0,iLen) ;return true ;}catch(Exception err) { MessageBox.Show("接收文件失败"+err.Message) ; return false ; }finally { fs.Close() ; }}}//end class}//end namespace上面是俺的通讯基础类,有了这个类,再进行发送接受还不是小菜一碟吗?上面介绍了通讯的基类,下面就是使用那个类进行发送和接收的部分:二、发送部分:发送咱们使用了多线程,可以同时进行多个任务,比如发送文件、发送文本等,互不影响:发送文本方法:private void StartSendText(string strHost,int iPort,string strInfo){SendText stText = new SendText(strHost,iPort,strInfo,new CommunClass.OnSend(OnSendDrawProgress)) ; StartThread(new ThreadStart(stText.Send)) ;}下面是他调用用到的一些方法:开始一个线程private void StartThread(ThreadStart target){Thread doStep = new Thread(target) ;doStep.IsBackground = true ;doStep.Start() ;}发送一部分(本文设置的是1024字节)成功后的回调方法public void OnSendDrawProgress(int iTotal,int iSending){if (iTotal != pbMain.Maximum)pbMain.Maximum = iTotal ;pbMain.V alue = iSending ;}因为使用的是线程,所以发送文本使用的是一个发送文本类的方法,该类如下:public class SendText{private string Host ;private int Port ;private string Info ;private CommunClass.OnSend onsend ;public SendText(string strHost,int iPort,string strInfo, CommunClass.OnSend onSend){Host = strHost ;Port = iPort ;Info = strInfo ;onsend = onSend ;}public void Send(){Socket s = null ;try{s = CommunClass.ConnectToServer(Host,Port) ;CommunClass.WriteCommandToSocket(s,"SENDTEXT") ;CommunClass.WriteCommandDescToSocket(s,"") ;CommunClass.WriteDynamicTextToSocket(s,Info,onsend) ;}catch (Exception e) { MessageBox.Show(e.Message) ; }finally { if (s != null) s.Close() ; } }}//end class这样就可以使用一个线程发送文本了。
基于VC 的Winsock 的文件传输程序的设计环境要求:Windows95/98/2000/XP功能要求:能将键盘上指定的文件发送到另一台计算机上;能将接收到的数据显示到屏幕窗口内,并显示收到文件的字节数和文件传输速率;一、设计目标用TC、Visual BASIC、Visual C++、Java 等编程工具和路由器、交换机、主机等网络设备提供的接口,解决网络用户之间的交互式对话问题,或计算通信网络的延迟、信道容量分配,或编码分析、通信协议分析,网络互连互通、网络规划。
进一步深入掌握网络设计和通信程序的设计原理。
使学生对计算机通信网络的设计实现有较深的了解,培养较高的通信网络设计能力。
本课设实验将基于2013版Visual Studio进行WINSOCK的文件传输的编程实现。
在WINDOWS95/98,WINDOWSNT进行WINSOCK开发使用的编程语言有很多,VC++,JAVA,DELPHI,VB等。
其中VC时使用最普遍,和WINSOCK结合最紧密的。
并且VC++对原来的WindowsSockets 库函数进行了一系列封装,继而产生了CAsynSocket、CSocket、CSocketFile等类,它们封装着有关Socket的各种功能,是编程变得更加简单。
SOCKET实际在计算机中提供了一个通信端口,可以通过这个端口与任何一个具有SOCKET 接口的计算机通信。
应用程序在网络上传输,接收的信息都通过这个SOCKET接口来实现。
在应用开发中就像使用文件句柄一样,可以对SOCKET句柄进行读,写操作。
二、设计原理套接字(Socket) 是一种网络编程接口,它是对通信端点的一种抽象,提供了一种发送和接收数据的机制。
套接字有两种类型:流式套接字(St ream Socket s) 和数据报套接字(Datagram Socket s) 。
数据报套接字提供了一种不可靠的、非连接的数据包通信方式,它使用用户数据报协议(UDP) ;而流式套接字可以将数据按顺序无重复地发送到目的地,它提供的是一种可靠的面向连接的数据传输方式。
C上传⽂件到服务器(含接收端源码)实例向⼤家展⽰了如何⽤Visual C#实现⽹络⽂件的下载,使⽤Visual C#进⾏Internet通讯编程是⾮常⽅便的。
在上⾯的程序中,我们仅仅⽤到了WebClient类的⼀些⽅法,⽽WebClient类不光提供了⽹络⽂件下载的⽅法,还提供了⽂件上传的⽅法【实例简介】⼀.概述:本⽂通过⼀个实例向⼤家介绍⽤Visual C#进⾏Internet通讯编程的⼀些基本知识。
我们知道.Net类包含了请求/响应层、应⽤协议层、传输层等层次。
在本程序中,我们运⽤了位于请求/响应层的WebRequest类以及WebClient类等来实现⾼抽象程度的Internet通讯服务。
本程序的功能是完成⽹络⽂件的下载。
⼆.实现原理:程序实现的原理⽐较简单,主要⽤到了WebClient类和FileStream类。
其中WebClient类处于名字空间中,该类的主要功能是提供向URI标识的资源发送数据和从URI标识的资源接收数据的公共⽅法。
我们利⽤其中的DownloadFile()⽅法将⽹络⽂件下载到本地。
然后⽤FileStream类的实例对象以数据流的⽅式将⽂件数据写⼊本地⽂件。
这样就完成了⽹络⽂件的下载。
三.实现步骤:⾸先,打开Visual ,新建⼀个Visual C# Windows应⽤程序的⼯程,不妨命名为"MyGetCar"。
接着,布置主界⾯。
我们先往主窗体上添加如下控件:两个标签控件、两个⽂本框控件、⼀个按钮控件以及⼀个状态栏控件。
最终的主窗体如下图所⽰:完成主窗体的设计,我们接着完成代码的编写。
在理解了基本原理的基础上去完成代码的编写是相当容易。
程序中我们主要⽤到的是WebClient类,不过在我们调⽤WebClient类的实例对象前,我们需要⽤WebRequest类的对象发出对统⼀资源标识符(URI)的请求。
try{WebRequest myre=WebRequest.Create(URLAddress);}catch(WebException exp){MessageBox.Show(exp.Message,"Error");}这是⼀个try-catch语句,try块完成向URI的请求,catch块则捕捉可能的异常并显⽰异常信息。
目录前言 .............................................. 错误!未定义书签。
第一章 FTP简介..................................... 错误!未定义书签。
1.1 FTP传输机制............................... 错误!未定义书签。
1.2 FTP的数据类型............................. 错误!未定义书签。
第二章开发工具简介 ............................... 错误!未定义书签。
2.1 .C#简介.................................. 错误!未定义书签。
2.2. Visual Studio .NET........................ 错误!未定义书签。
2.2.1 Visual Studio .NET 的特色 (6)(1) 语言增强............................. 错误!未定义书签。
(2) Web 窗体............................. 错误!未定义书签。
(3) Windows 窗体......................... 错误!未定义书签。
(4) XML Web services..................... 错误!未定义书签。
(5) XML 支持............................. 错误!未定义书签。
2.3 .NET 框架................................. 错误!未定义书签。
第三章项目简介 ................................... 错误!未定义书签。
3.1 需求分析................................... 错误!未定义书签。
C#TcpClient⽹络编程传输⽂件的⽰例⽬录⼀、简述⼆、内容⼀、简述 利⽤C# TcpClient在局域⽹内传输⽂件,可是⽂件发送到对⾯的时候却要重新命名⽂件的。
那可不可以连着⽂件名与⽂件⼀起发过去呢?⼆、内容 如上图,把⽂件名字符流的长度的值的字符流(这个⽂件名字符流长度的值固定是11位的字符串,不⾜11位前⾯补0)与⽂件名的字符流合为⼀个byte数组然后与⽂件发送到对⾯。
对⾯接收后解析出⽂件名字符流长度的值后,再根据长度解析出⽂件名,接下来再获取⽂件流。
服务端using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.IO;using ;using .Sockets;using System.Text;using System.Threading;using System.Windows.Forms;namespace TCPSendFile{public partial class Form1 : Form{public delegate void TxtReceiveAddContentEventHandler(string txtValue);public Form1(){InitializeComponent();}public void TxtAddContent(string txtValue){if (textBox1.InvokeRequired){TxtReceiveAddContentEventHandler addContent = TxtAddContent;textBox1.Invoke(addContent, new object[] { txtValue });}else{textBox1.Text = txtValue + "\r\n" + textBox1.Text;}}private void button1_Click(object sender, EventArgs e){TcpListener tcpListener = new TcpListener(IPAddress.Any, 18001);tcpListener.Start();textBox1.Text = "开始侦听...";Thread thread = new Thread(SendFileFunc);thread.Start(tcpListener);thread.IsBackground = true;}public void SendFileFunc(object obj){TcpListener tcpListener = obj as TcpListener;while (true){try{TcpClient tcpClient = tcpListener.AcceptTcpClient();if (tcpClient.Connected){NetworkStream stream = tcpClient.GetStream();string fileName = "testfile.rar";byte[] fileNameByte = Encoding.Unicode.GetBytes(fileName);byte[] fileNameLengthForValueByte = Encoding.Unicode.GetBytes(fileNameByte.Length.ToString("D11")); byte[] fileAttributeByte = new byte[fileNameByte.Length + fileNameLengthForValueByte.Length];fileNameLengthForValueByte.CopyTo(fileAttributeByte, 0); //⽂件名字符流的长度的字符流排在前⾯。
建议读者再看实验步骤之前,先阅读一下文章末尾的【注意事项】一节。
这将有助于更好的理解本章的实现。
一.单线程文件传输(I):·服务器端(负责发送数据)的实现1.建立一个基于对话框的工程Server,并在建立的过程中选择支持windows socket。
2.在对话框上添加“发送”按钮。
3.为“发送”按钮添加事件BN_CLICKED的响应函数OnSend()。
void CServerDlg::OnSend(){//TODO:Add your control notification handler code hereCFileDialog fd(TRUE);//CFileDialog是MFC提供的一个用于选择文件的对话框类CString filename;char fn[40];CSocket listenSocket,socketSend;CFile file;long FileLength;char*data;if(IDOK==fd.DoModal())//启动用于选择文件的对话框{//选择了文件filename=fd.GetFileName();//获取用户选择的文件的文件名if(!file.Open(filename.GetBuffer(0),CFile::modeRead|File::typeBinary)){AfxMessageBox("打开文件错误,取消发送!");return;}strcpy(fn,filename.GetBuffer(0));}else return;//按了取消按钮listenSocket.Create(7000,SOCK_STREAM);listenSocket.Listen(5);listenSocket.Accept(socketSend);FileLength=file.GetLength();//获取文件的长度socketSend.Send(&FileLength,4);//把要发送的文件的长度传送给对方socketSend.Send(fn,40);//发送要传送的文件的文件名data=new char[FileLength];//分配一块和要传输的文件一样大小的内存空间file.ReadHuge(data,FileLength);//把文件中所有的数据一次性读入datasocketSend.Send(data,FileLength);//把data中的数据都发送出去file.Close();delete data;socketSend.Close();}·客户端(负责接收数据)的实现1.建立一个基于对话框的工程,并在建立的过程中选择支持windows socket。
建议读者再看实验步骤之前,先阅读一下文章末尾的【注意事项】一节。
这将有助于更好的理解本章的实现。
一.单线程文件传输(I):·服务器端(负责发送数据)的实现1.建立一个基于对话框的工程Server,并在建立的过程中选择支持windows socket。
2.在对话框上添加“发送”按钮。
3.为“发送”按钮添加事件BN_CLICKED的响应函数OnSend()。
void CServerDlg::OnSend(){// TODO: Add your control notification handler code hereCFileDialog fd(TRUE); // CFileDialog是MFC提供的一个用于选择文件的对话框类CString filename;char fn[40];CSocket listenSocket, socketSend;CFile file;long FileLength;char* data;if(IDOK==fd.DoModal()) // 启动用于选择文件的对话框{//选择了文件filename=fd.GetFileName(); // 获取用户选择的文件的文件名if(!file.Open(filename.GetBuffer(0),CFile::modeRead| File::typeBinary)){AfxMessageBox(" 打开文件错误,取消发送!");return;}strcpy(fn,filename.GetBuffer(0));}else return; //按了取消按钮listenSocket.Create(7000,SOCK_STREAM);listenSocket.Listen(5);listenSocket.Accept(socketSend);FileLength = file.GetLength(); // 获取文件的长度socketSend.Send(&FileLength, 4); // 把要发送的文件的长度传送给对方socketSend.Send(fn,40); // 发送要传送的文件的文件名data = new char[FileLength]; //分配一块和要传输的文件一样大小的内存空间file.ReadHuge(data, FileLength); //把文件中所有的数据一次性读入datasocketSend.Send(data, FileLength); //把data中的数据都发送出去file.Close();delete data;socketSend.Close();}·客户端(负责接收数据)的实现1.建立一个基于对话框的工程,并在建立的过程中选择支持windows socket。
(为了能够利用Server端的代码,在程序编写时,可以复制Server的代码到Client目录,并在Server的基础上修改或添加代码)2.在对话框上添加“接收”按钮。
3.为“发送”按钮添加事件BN_CLICKED的响应函数OnReceive ()。
void CServerDlg::OnReceive(){// TODO: Add your control notification handler code hereCSocket socketReceive;CFile file;long FileLength;char * data;char fn[40];socketReceive.Create();socketReceive.Connect("127.0.0.1", 7000); //这里为了测试的方便,我们使用127.0.0.1本地回路IPsocketReceive.Receive(&FileLength, 4); //获取要接受的文件的长度socketReceive.Receive(fn, 40); //获取要接受的文件的文件名data = new char[FileLength];socketReceive.Receive(data, FileLength); //获取要接受的文件内容file.Open(fn,CFile::modeCreate|CFile::modeWrite | CFile::typeBinary); //在当前目录建立文件file.WriteHuge(data, FileLength);file.Close();delete data;socketReceive.Close();AfxMessageBox("接收文件成功");}上面的程序以最简单的方式实现了文件传输功能。
但正是因为它的简单,所以忽略了很多重要的东西。
读者读到这里的时候可以考虑一下可能存在着些什么问题。
在这里给出一些上面程序的不足:1.在本书的原理部分曾经提到阻塞式和非阻塞式两种套接字的工作方式。
在上面的程序中使用的CSocket类提供了阻塞式的服务,这令编写程序非常方便。
然而这却不利于程序的友好性和可用性——服务器端在没有获得客户端连接的时候固执的侦听,一点也不理会用户的命令。
对话框不再响应消息,用户只能用强制关闭来结束程序。
2.希望一次性地动态分配整个文件大小的堆存贮区作为读入数据的内存空间。
这个空间一方面受到堆大小的限制,另一方面也受到CFile类成员函数ReadHuge()和WriteHuge()的读写能力限制,还有Receive()和Send()函数一次能够发送的数据也以其参数的最大值为限,所以在遇到大中型文件的时候,系统将不能满足程序提出的动态分配大块内存的要求,这样传输便不得不终止。
3.在实际的网络传输中,网络情况是十分多变和复杂的。
通过CSocket的成员函数们的返回值可以了解传输的状态,然而在上面的程序中却没有使用这些异常控制,带来的直接后果就是当遇到网络拥塞或对方传送的数据暂时未到时,程序就会认为传输结束而出乎意料的终止。
4.在上面的程序中,程序没有传送文件的属性数据,而只通过套接字传送文件数据。
在实际应用中这种假设通常是不存在的,所以应当把文件属性也传给对方,以达到文件的完全复制。
改进方法:1.使用CAsyncSocket实现异步套接字,避免阻塞2.化整为零,把文件分若干次读入并发送3.在程序中加入异常控制语句已应付网络多变的情况4.在传送文件数据之前获取文件属性值传给对方下面将给出基于上述改进方案的前三点而重新编写的程序,对于第四点,有兴趣的读者可以自己实现。
二.单线程文件传输(II):·服务器端(负责发送数据)的实现1.建立一个基于对话框的工程Server,并在建立的过程中选择支持windows socket。
2.在对话框上添加“侦听”,“发送”按钮。
3.用Class Wizard添加一个派生于CAsyncSocket的类CMySocket。
4.添加CMySocket类的全局变量listenSocket用于侦听。
添加CMySocket类全局变量的位置,最宜在MySocket.cpp的头部。
如下:// MySocket.cpp : implementation file//#include "stdafx.h"#include "Server.h"#include "MySocket.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// CMySocketCMySocket listenSocket;CMySocket::CMySocket(){}CMySocket::~CMySocket(){}本章中以后所有的CMySocket型全局变量都应仿效本段程序添加。
5.添加CMySocket类的全局变量sendSocket,用于传输数据6.为“发送”按钮添加事件BN_CLICKED的响应函数OnSend() #define ReadSize 500void CServerDlg ::OnSend(){// TODO: Add your control notification handler code hereCFile file;char data[ReadSize]; // 用于存放读入的文件数据块long ByteSended=0, FileLength,count;CFileDialog fd(TRUE);CString filename;char fn[40];if(IDOK==fd.DoModal()) // 启动用于选择文件的对话框{//选择了文件filename=fd.GetFileName(); //获取选择的文件的文件名if(!file.Open(filename.GetBuffer(0),CFile::modeRead|CFile::typeBinary)){AfxMessageBox("打开文件错误,取消发送!");return;}strcpy(fn,filename.GetBuffer(0));}else return; //按了取消按钮FileLength=file.GetLength();sendSocket.Send(&FileLength,sizeof(long));sendSocket.Send(fn,40);memset(data,0,sizeof(data));do{// 从文件读取数据,每次最多读入ReadSize个字节。
count 表示实际读入的字节数count=file.ReadHuge(data, ReadSize);// 发送数据while(SOCKET_ERROR==sendSocket.Send(data,count)){}// 统计已发送的字节数ByteSended =ByteSended+count;}while(ByteSended <FileLength);file.Close();}7.为“侦听”按钮添加事件BN_CLICKED的响应函数OnListen () void CServerDlg::Listen(){// TODO: Add your control notification handler code herelistenSocket.Create(7000);listenSocket.Listen();}8.为CMySocket类添加消息OnAccpet响应函数OnAccept()void CMySocket::OnAccept(int nErrorCode){// TODO: Add your specialized code here and/or call the base classif(!listenSocket.Accept(sendSocket)){AfxMessageBox("连接失败");return;}AfxMessageBox("连接成功");CAsyncSocket::OnAccept(nErrorCode);}·客户端(负责接收数据)的实现1.建立一个基于对话框的工程,并在建立的过程中选择支持windows socket。