如何通过Socket TCP发送并接收一个文件?

一.小结

1.大包发小包收,只发一次。

2.发时把文件扩展名,文件长度也随同一起发送,方便接收端接收时另存为正确的文件类型,并判断是否已经接收完毕。

如果不一起发送,分为文件扩展名,文件长度,文件内容,发送三次,在接收端,也可能会一起收到,反而不利于解析。

二.客户发送端代码

        private void btnSend_Click(object sender, EventArgs e)
        {
            //组合出远程终结点
            IPAddress ipAddress = IPAddress.Parse(this.txtIP3.Text);
            IPEndPoint hostEP = new IPEndPoint(ipAddress, Convert.ToInt32(this.txtPort3.Text));
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                socket.Connect(hostEP);

                //1.发送用户协议
                string path1 = Environment.CurrentDirectory; //获取应用程序的当前工作目录。
                string doc = "YourSendFile.pdf";
 string path = Path.Combine(path1, doc);
                FileStream fs = File.Open(path, FileMode.Open);

                //文件内容
                byte[] bdata = new byte[fs.Length];
                fs.Read(bdata, 0, bdata.Length);
                fs.Close();

                //文件扩展名,固定3字节
                byte[] fileExtArray = Encoding.UTF8.GetBytes(string.Format("{0:D3}", currentDocExt));

                //文件长度, 固定为20字节,前面会自动补零
                byte[] fileLengthArray = Encoding.UTF8.GetBytes(bdata.Length.ToString("D20"));

                //合并byte数组
                byte[] fileArray = CombomBinaryArray(fileExtArray, fileLengthArray);

                //合并byte数组
                byte[] bdata1 = CombomBinaryArray(fileArray, bdata);

                //发文件长度+文件内容
                socket.Send(bdata1, bdata1.Length, 0);

                //2.接收
                //声明接收返回内容的字符串
                string recvStr = "";

                //声明字节数组,一次接收数据的长度为 1024 字节
                byte[] recvBytes = new byte[1024];

                //返回实际接收内容的字节数
                int bytes = 0;

                //循环读取,直到接收完所有数据
                while (true)
                {
                    bytes = socket.Receive(recvBytes, recvBytes.Length, 0);
                    //读取完成后退出循环
                    if (bytes <= 0) break;

                    //将读取的字节数转换为字符串
                    recvStr += Encoding.UTF8.GetString(recvBytes, 0, bytes);
                }              

                //禁用 Socket
                socket.Shutdown(SocketShutdown.Both);

                //关闭 Socket
                socket.Close();

                //... do some busness logic ...

            }
            catch (Exception e1)
            {
                throw e1;
            }
        }

三.服务接收端代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Xml;
using System.Configuration;
using System.Windows.Forms;
using System.IO;

namespace ConsoleAppServer
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {

            bool Done = false;
            IPAddress ipAddress = IPAddress.Parse(ConfigurationSettings.AppSettings["IP"].ToString());
            IPEndPoint hostEP = new IPEndPoint(ipAddress, Convert.ToInt32(ConfigurationSettings.AppSettings["Port"]));
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Bind(hostEP);
            socket.Listen(3);
            while (!Done)
            {
                Console.WriteLine("waiting for client");

                Socket client = socket.Accept();

                Console.WriteLine("connected client");

                //1.接收
                //声明字节数组,一次接收数据的长度为 1024 字节
                byte[] recvBytes = new byte[1024];
                //返回实际接收内容的字节数
                int bytes = 0;

                int FileLength = 0; // 900866;
                int ReceivedLength = 0;

                //1.0 接收文件扩展名
                bytes = client.Receive(recvBytes, 3, 0);
                string fileExt = Encoding.UTF8.GetString(recvBytes, 0, bytes);

                string vFilePath = Environment.CurrentDirectory;
                string vFileName = vFilePath + "\\Tmp" + Guid.NewGuid().ToString() + "." + fileExt;

                //创建文件流,然后让文件流来根据路径创建一个文件
                FileStream fs = new FileStream(vFileName, FileMode.Create);

                //1.1 接收文件长度
                bytes = client.Receive(recvBytes, 20, 0);
                //将读取的字节数转换为字符串
                string fileLength = Encoding.UTF8.GetString(recvBytes, 0, bytes);
                FileLength = Convert.ToInt32(fileLength);

                //1.2接收文件内容
                while (ReceivedLength < FileLength)
                {
                    bytes = client.Receive(recvBytes, recvBytes.Length, 0);
                    ReceivedLength += bytes;
                    fs.Write(recvBytes, 0, bytes);
                }

                fs.Flush();
                fs.Close();

                //... do some business logic ...
               string returnData = SomeBusinessLogic();

                //2.发送
                byte[] bdata = Encoding.UTF8.GetBytes(returnData);
                client.Send(bdata, bdata.Length, 0);

                client.Close();
            }

            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
        }

    }
}
时间: 2024-08-24 06:39:11

如何通过Socket TCP发送并接收一个文件?的相关文章

php发送 与接收流文件

PHP 发送与接收流文件 sendStreamFile.php 把文件以流的形式发送 receiveStreamFile.php 接收流文件并保存到本地 sendStreamFile.php <?php /** php 发送流文件 * @param  String  $url  接收的路径 * @param  String  $file 要发送的文件 * @return boolean */ function sendStreamFile($url, $file){ if(file_exists

php 发送与接收流文件

<?php /** php 发送流文件 * @param String $url 接收的路径 * @param String $file 要发送的文件 * @return boolean */ function sendStreamFile($url, $file){ if(file_exists($file)){ $opts = array( 'http' => array( 'method' => 'POST', 'header' => 'content-type:applic

?TCP发送与接收数据

//客户端 package liu.net.tcp; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class Client { /* tcp 客户端建立的步骤 * 1.建立tcp客户端服务 * 1.1 因为是面向连接的,必须有连接才可以进行通信 * 1.2在建立客户端时,必须明确目的地地址和

Java 通过Socket编程 发送和接收数据

Socket client = null; try{     client = new Socket(Ip,Port);     String msg="发送的数据内容!";     //得到socket读写流,向服务端程序发送数据       client.getOutputStream().write(msg.getBytes());     byte[] datas = new byte[2048];     //从服务端程序接收数据     client.getInputStr

TCP二进制流接收

前几天,模拟了一个tcp发送与接收16进制的小程序.由于需求的改变现在需要接收二进制流式数据,下面记录一下客户端接收数据的实现的源码. package client; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.net.Socket; public class ClientSocket { static Socket socket = nul

socket 错误之:OSError: [WinError 10057] 由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。

出错的代码 #server端 import socket import struct sk=socket.socket() sk.bind(('127.0.0.1',8080)) sk.listen() conn,addr=sk.accept() str_len1=struct.unpack('i',conn.recv(4))[0] print(sk.recv(str_len1)) str_len2=struct.unpack('i',conn.recv(4))[0] print(sk.recv

C#Socket文件传输(发送与接收代码)

这里是发送的代码: SendVarData是转码后发送函数 1 /// <summary> 2 /// 发送文件 3 /// </summary> 4 /// <param name="userName"></param> 5 private void SendFileToClient(string userName) 6 { 7 User targetUser = userListDict[userName]; 8 String tar

TCP发送接收数据(一)

TCP发送接收数据 import java.io.IOException; import java.io.OutputStream; import java.net.Socket; /* * TCP协议发送数据: * A:创建发送端的Socket对象 *    这一步如果成功,就说明连接已经建立成功了. * B:获取输出流,写数据 * C:释放资源 * * 连接被拒绝.TCP协议一定要先看服务器. * java.net.ConnectException: Connectionrefused: c

从缓冲上看阻塞与非阻塞socket在发送接收上的区别

最近在网络上看到一些帖子以及回复,同时又搜索了一些网络上关于阻塞非阻塞区别的描述,发现很多人在描述两者的发送接收时操作返回以及缓冲区处理的区别时有不同程度的误解.所以我想写一篇文章来纠正错误,并作为记录方便查阅,如有转载,注明作者(jwybobo2007)以及出处即可. 首先socket在默认情况下是阻塞状态的(未指异步操作以及其它一些特殊用途下,直接默认为非阻塞),这就使得发送以及接收操作处于阻塞的状态,即调用不会立即返回,而是进入睡眠等待操作完成.下面把讨论点分为发送以及接收.  一.发送选