程序简介
基于网友的提议,最近有点时间,便打算给之前的聊天程序增加一个功能-文件发送.
原理
文件发送跟字符串信息发送的原理其实是一样的,都是通过将需要发送的数据转换成计算机可以识别的字节数组来发送.当然,计算机本身并不知道你发送的是字符串信息还是文件,所以我们首先需要告诉计算机哪个发送的是文件,哪个是字符串信息;这里分别给它们的字节数组附加了一个类型标识符:字符串信息的字节数组标识符为0,文件的字节数组标识符为1.当一端将文件发送过去后,另一端则首先判断发送过来的类型标识符(1或者0),然后再调用相应的方法将获取的字节数组转换成人可以看懂的字符串信息或文件.
界面设计 - 客户端
这里新增了3个控件,用于实现文件发送功能.
Textbox: 文件名name: txtFileName
Button: 选择文件name: btnSelectFile 发送文件name: btnSendFile
代码实施 - 客户端
首先,我们需要写一个选择发送文件的方法,这里使用了最常见OpenFileDialog方法,用于选取需要发送的文件.
1 2 3 4 5 6 7 8 9 10 11 12 13
| string filePath = null; string fileName = null;
private void btnSelectFile_Click(object sender, EventArgs e) { OpenFileDialog ofDialog = new OpenFileDialog(); if (ofDialog.ShowDialog(this) == DialogResult.OK) { fileName = ofDialog.SafeFileName; txtFileName.Text = fileName; filePath = ofDialog.FileName; } }
|
选取文件之后,我们先发送文件的名称和长度, 然后再发送文件.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
private void SendFile(string fileFullPath) { if (string.IsNullOrEmpty(fileFullPath)) { MessageBox.Show(@"请选择需要发送的文件!"); return; }
long fileLength = new FileInfo(fileFullPath).Length; string totalMsg = string.Format("{0}-{1}", fileName, fileLength); ClientSendMsg(totalMsg, 2);
byte[] buffer = new byte[SendBufferSize];
using (FileStream fs = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read)) { int readLength = 0; bool firstRead = true; long sentFileLength = 0; while ((readLength = fs.Read(buffer, 0, buffer.Length)) > 0 && sentFileLength < fileLength) { sentFileLength += readLength; if (firstRead) { byte[] firstBuffer = new byte[readLength + 1]; firstBuffer[0] = 1; Buffer.BlockCopy(buffer, 0, firstBuffer, 1, readLength);
socketClient.Send(firstBuffer, 0, readLength + 1, SocketFlags.None);
firstRead = false; continue; } socketClient.Send(buffer, 0, readLength, SocketFlags.None); } fs.Close(); } txtMsg.AppendText("SoFlash:" + GetCurrentTime() + "\r\n您发送了文件:" + fileName + "\r\n"); }
|
代码实施 - 服务端
服务端接受字符串信息,文件名称和长度以及文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| string strSRecMsg = null;
private void ServerRecMsg(object socketClientPara) { Socket socketServer = socketClientPara as Socket;
long fileLength = 0; while (true) { int firstReceived = 0; byte[] buffer = new byte[ReceiveBufferSize]; try { if (socketServer != null) firstReceived = socketServer.Receive(buffer);
if (firstReceived > 0) { if (buffer[0] == 0) { strSRecMsg = Encoding.UTF8.GetString(buffer, 1, firstReceived - 1); txtMsg.AppendText("SoFlash:" + GetCurrentTime() + "\r\n" + strSRecMsg + "\r\n"); } if (buffer[0] == 2) { string fileNameWithLength = Encoding.UTF8.GetString(buffer, 1, firstReceived - 1); strSRecMsg = fileNameWithLength.Split('-').First(); fileLength = Convert.ToInt64(fileNameWithLength.Split('-').Last()); } if (buffer[0] == 1) { string fileNameSuffix = strSRecMsg.Substring(strSRecMsg.LastIndexOf('.')); SaveFileDialog sfDialog = new SaveFileDialog() { Filter = "(*" + fileNameSuffix + ")|*" + fileNameSuffix + "", FileName = strSRecMsg };
if (sfDialog.ShowDialog(this) == DialogResult.OK) { string savePath = sfDialog.FileName; int received = 0; long receivedTotalFilelength = 0; bool firstWrite = true; using (FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Write)) { while (receivedTotalFilelength < fileLength) { if (firstWrite) { fs.Write(buffer, 1, firstReceived - 1); fs.Flush();
receivedTotalFilelength += firstReceived - 1;
firstWrite = false; continue; } received = socketServer.Receive(buffer); fs.Write(buffer, 0, received); fs.Flush();
receivedTotalFilelength += received; } fs.Close(); }
string fName = savePath.Substring(savePath.LastIndexOf("\\") + 1); string fPath = savePath.Substring(0, savePath.LastIndexOf("\\")); txtMsg.AppendText("天之涯:" + GetCurrentTime() + "\r\n您成功接收了文件" + fName + "\r\n保存路径为:" + fPath + "\r\n"); } } } } catch (Exception ex) { txtMsg.AppendText("系统异常消息:" + ex.Message); break; } } }
|
运行程序
首先,启动服务端并持续监听客户端对其的连接,当客户端成功连接上服务端之后,两端便可以开始通信了.
两端建立连接之后,便可以开始互相通信了.
简单的两端对聊之后, 本人便打算发送个文件过去.
选取了一本张道真的语法书,后缀为.pdf(文件类型)
当点击发送文件按钮后,客户端聊天内容中显示”您发送了文件:张道真实用英语语法.pdf”.
这时服务端收到文件后,程序弹出一个另存为对话框,用于保存接收到的文件.这里我们可以看到系统自动附加上了文件名和保存类型.
当服务端用户接收并保存文件之后,聊天内容里显示”您成功接收了文件张道真实用英语语法.pdf” 以及文件的保存路径.
附上源代码
服务端 ChatServer2.zip 客户端 ChatClient2.zip
转自:https://www.cnblogs.com/longwu/archive/2011/08/25/2153636.html