用socket传输文件时带上文件名

做C#开发,很多场景需要传输文件,socket是一个不错选择,想想办法还能带上文件名。网上类似的文章也很多,但是好像有效的不多,完整的代码几乎没有。于是乎,我来贴一个,高手不要吐槽哦,因为这个简单而又简约的文章,也许、大概能帮助某些初学者嘛。服务端和客户端代码都在这里了。

服务端接收文件代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.IO;
using blank.Log;
using System.Threading;
using blank.Tools;
using System.Collections.Concurrent;

namespace FileSysServer
{
    public class tcpServerSocket 
    {
       
        private TcpListener listener;
        
        public void Start()
        {
           
            listener = new TcpListener(IPAddress.Any, 8888);
            listener.Start();//开始监听客户端的请求
           
            while (true)
            {
                try
                {
                    TcpClient tcpClient = listener.AcceptTcpClient();
                    if (tcpClient != null && tcpClient.Client != null)
                    {
                        Thread thread = new Thread(ReceiveMsg); //用一个线程单独处理这个连接
                        thread.Start(tcpClient);
                    }
                }
                catch (Exception e)
                {
                    LogHelper.WriteLog("接到请求发生错误" + e.Message);
                }
            }
        }

       
        #region ReceiveMsg
        private void ReceiveMsg(object o)
        {
            TcpClient c = (TcpClient)o;

            while (true)
            {
                try
                {
                    if (c == null || c.Client == null || !IsSocketConnected(c.Client))
                    {
                        Close(c);
                        break;
                    }

                   NetworkStream ns = c.GetStream();
                   if (ns != null)
                   {
                       StreamReader sr = new StreamReader(ns, Encoding.UTF8);
                       if (sr != null)
                       {
                           string result = sr.ReadToEnd();

                           if (string.IsNullOrEmpty(result) || result.Length < 10)
                           {
                               //伪心跳机制 发个0 回个1
                               c.Client.Send(Encoding.UTF8.GetBytes("1"));//
                           }
                           else
                           {
                               Task.Factory.StartNew(() => createFile(result));
                           }
                       }

                       if (sr != null)
                       {
                           sr.Close();
                           sr = null;
                       }
                   }

                   if (ns != null)
                   {
                       ns.Close();
                       ns = null;
                   }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLog("异常2:" + ex.Message);
                    break;
                }
            }
        }
        #endregion

        #region 创建文件
        private void createFile(string reveiceName)
        {
            try
            {
                //@@@
                int pos = reveiceName.IndexOf("@@@");
                if (pos < 0)
                {
                    LogHelper.WriteLog("文件内容错误");
                    return;
                }

                string fileName = reveiceName.Substring(0, pos);
                if (string.IsNullOrEmpty(fileName) || fileName.Length < 10)
                {
                    LogHelper.WriteLog("文件名错误");
                    return;
                }

                //解密文件名
                //if (bool.Parse(MonitorPwd))
                //{
                //    fileName = Encrypt.MD5Decrypt(fileName);
                //}

                string fileContent = reveiceName.Substring(pos + 3);
               
                string fullPath = Path.Combine("D:\test", fileName);//获取存储路径及文件名

                FileStream filesave = new FileStream(fullPath, FileMode.Create, FileAccess.Write);//创建文件流,用来写入数据
                    
                    byte[] arrMsg = Encoding.UTF8.GetBytes(fileContent);

                    //filesave.WriteByte(arrMsg);

                    filesave.Write(arrMsg, 0, arrMsg.Length);//将数据写入到文件中
                    
                    filesave.Close();

                   // fm.AddMsg(fullPath);
                
            }
            catch (Exception e)
            {
                LogHelper.WriteLog("创建文件发生错误" + e.Message);
            }
        }
        #endregion

        #region close
        private void Close(TcpClient c)
        {
            if (c == null || c.Client == null)
            {
                return;
            }

            try
            {
                c.Client.Shutdown(SocketShutdown.Both);
                c.Client.Close();
                c.Client = null;

                c.Close();
                c = null;
            }
            catch (Exception e)
            {
                LogHelper.WriteLog("关闭TcpClient失败" + e.Message);
            }
        }
        #endregion

        #region IsSocketConnected
         //这个方法网上找来的,如有雷同,纯属抄袭
        private bool IsSocketConnected(Socket client)
        {
            bool blockingState = client.Blocking;
            try
            {
                byte[] tmp = new byte[1];
                client.Blocking = false;
                client.Send(tmp, 0, 0);
                return true;
            }
            catch (SocketException e)
            {
                // 产生 10035 == WSAEWOULDBLOCK 错误,说明被阻止了,但是还是连接的
                if (e.NativeErrorCode.Equals(10035))
                    return false;
                else
                    return true;
            }
            finally
            {
                client.Blocking = blockingState;    // 恢复状态
            }
        }
        #endregion
    }
}

客户端发送文件代码

public static string SendFileData(string fileName)
        {
            TcpClient c = new TcpClient();
            try
            {
                //Thread.Sleep(1000);
                byte[] byteArray = Readbytes(fileName);

                if (byteArray == null)
                {
                    return string.Format("读取文件{0}失败", fileName);
                }
                
                c.Connect(IPAddress.Parse("127.0.0.1"), 8888); //部署的时候自己换iP
                c.Client.Send(byteArray);//将读取成功的文件发送给SocketServer服务器 

                return "";
            }
            catch (Exception e)
            {
                return e.Message;
            }
            finally 
            {
                Close(c);  //这个关闭方法和服务端的那个是一样的,自己复制粘贴吧
            }
        }

这里有人可能会说,每一次都打开、关闭,不是长连接,效率不高啊,确实如此。开一个连接,然后一直传,不好吗?因为是传输文件,不是传文字内容,用一个socket发现有各种问题。可能有更好的写法,懒得研究了。这里暂时满足客户场景,也算稳定,不研究了。不过,如果有更好的代码,欢迎吐槽。

读取文件内容,这个代码自己随便修改,与Socket发送和接收没关系。这里也贴出来,方便大家测试,看看效果

 #region 读文件
        private static byte[] Readbytes(string fullName)
        {
            FileStream fs = null;

            try
            {
                fs = new FileStream(fullName, FileMode.Open, FileAccess.Read);
                //创建文件流,用来读取数据

                string filename = Path.GetFileName(fullName);//提取文件名
                

                //是否加密
                //bool MonitorPwd = false;
                //if (bool.Parse(MonitorPwd))
                //{
                 //   filename = Encrypt.MD5Encrypt(filename);
                //}

                byte[] arrFile = new byte[fs.Length]; //定义缓存控件,长度为文件长度

                int length = fs.Read(arrFile, 0, arrFile.Length);//将文件读入缓存空间

                string fn = string.Concat(filename, "@@@", Encoding.UTF8.GetString(arrFile, 0, length));

                return Encoding.UTF8.GetBytes(fn);
            }
            catch (Exception e)
            {
                LogHelper.WriteLog("读文件失败" + e.Message);
                return null;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                    fs = null;
                }
            }
        }
        #endregion

这个传输办法其实就是用几个特殊字符 @@@ 把文件名和文件内容连接在一起,如果文件名同样含有@@@特殊符号,就麻烦了。至于文件内容里面有这个特殊符号时不影响的。   

文件名也可以做加密,解密处理,与传输没关系,所以注释了。

这个方法所传输的文件,没有那种超大文件,超大文件得想别的办法了。

 写日志方法那个语句,如果没有,注释即可  // LogHelper.WriteLog("读文件失败" + e.Message);

一个服务端,可以带多个客户端,本人实际运行场景就是这样的。一个服务端大概有7个客户端

补充一下,客户端代码的 using 

using System;
using System.Collections.Generic;
using blank.Tools;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值