C#通过Socket实现多文件传输

大概需求是客户端发送一个xml文件名给服务器,服务器返回xml文件。这一步没问题。
后面客户端需要解析xml文件,根据解析出的文件名,去服务器获取指定文件。现在问题是第一次服务器发送xml文件之后就侦听不到客户端后面的请求了
服务端代码:

#region 窗体加载
        private void Form1_Load(object sender, EventArgs e)
        {
            Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//Socket设置、IPv4、Stream类型套接字、TCP协议
            IPAddress ip = IPAddress.Any;//获取本机IP
            IPEndPoint point = new IPEndPoint(ip, 18002);//设置IP和端口
            socketWatch.Bind(point);//绑定端口
            memoEdit1.Text = "开始侦听...";
            socketWatch.Listen(100);//最大连接数
            Thread th = new Thread(SendFileFuncssss);//创建新线程
            th.Start(socketWatch);//启动线程
            th.IsBackground = true;//设置后台运行线程
        }
        #endregion

        #region 根据客户端传输文件名发送指定文件
        public void SendFileFuncssss(object obj)
        {
            Socket socket = obj as Socket;
            while (true)
            {
                Socket socketServices = socket.Accept();
                byte[] buffer = new byte[1024];
                int num = socketServices.Receive(buffer);//接收到字节数
                string str = Encoding.UTF8.GetString(buffer, 1, num - 1);//接收到字符串
                if (buffer[0] == 0)//表示接收到的是消息数据
                {
                    TxtAddContent(socketServices.RemoteEndPoint + "连接成功");
                    string FileName = str;
                    if (FileName.Equals("AutoUpdater.xml"))//获取xml配置文件
                    {
                        //发送XML文件到客户端
                        using (FileStream fs = new FileStream(AppDomain.CurrentDomain.BaseDirectory + FileName, FileMode.Open))
                        {
                            byte[] arrFile = new byte[1024 * 1024 * 5];
                            int length = fs.Read(arrFile, 0, arrFile.Length);
                            byte[] arrFileSend = new byte[length + 1];
                            arrFileSend[0] = 1; // 用来表示发送的是xml文件数据
                            Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, length);
                            socketServices.Send(arrFileSend);// 发送数据到客户端
                        }
                    }
                    if (!FileName.Equals("AutoUpdater.xml"))
                    {
                        //发送更新文件到客户端
                        using (FileStream fs = new FileStream(AppDomain.CurrentDomain.BaseDirectory + "\\FileFolder\\" + FileName, FileMode.Open))
                        {
                            byte[] arrFile = new byte[1024 * 1024 * 50];
                            int length = fs.Read(arrFile, 0, arrFile.Length);//获取文件长度
                            byte[] arrFileSend = new byte[length + 1];
                            arrFileSend[0] = 1; // 用来表示发送的是xml文件数据
                            Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, length);
                            socketServices.Send(arrFileSend);// 发送数据到服务端
                        }
                    }
                }
            }
        }
        #endregion

客户端代码:

 Socket socketClient = obj as Socket;
            socketClient.Connect(ipEndPoint);

            #region 修改本地文件名称
            string Oldpath = AppDomain.CurrentDomain.BaseDirectory + "AutoUpdater.xml";//修改前名称
            string Newpath = AppDomain.CurrentDomain.BaseDirectory + "AutoUpdater_Back.xml";//修改后名称
            if (File.Exists(Oldpath))
            {
                File.Delete(Newpath);
                File.Move(Oldpath, Newpath);//更改文件名
            }
            #endregion

            if (socketClient.Connected)
            {
                try
                {
                    TxtReceiveAddContent("连接成功");
                    //发送链接成功提示
                    byte[] arrMsg = Encoding.UTF8.GetBytes("AutoUpdater.xml");
                    byte[] arrSendMsg = new byte[arrMsg.Length + 1];//加一位标识用于表示是文字消息还是文件
                    arrSendMsg[0] = 0; // 用来表示发送的是消息数据
                    Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);
                    socketClient.Send(arrSendMsg);
                    //获取文件
                    string dirPath = Application.StartupPath;
                    byte[] buffer = new byte[1024 * 1024 * 5];
                    int lenght = socketClient.Receive(buffer);
                    if (buffer[0] == 1)
                    {
                        using (FileStream fs = new FileStream(dirPath + "\\AutoUpdater.xml", FileMode.Create))
                        {
                            fs.Write(buffer, 1, lenght - 1);
                        }
                        TxtReceiveAddContent("配置文件接收成功:AutoUpdater.xml");//追加提示备注
                    }

                    #region 获取XML里需要更新的文件和需要删除的文件
                    List<string> updatelist = new List<string>();//需要更新的文件集合
                    List<string> deletelist = new List<string>();//需要更新的文件集合
                    //获取历史xml文件更新时间以及更新版本
                    XDocument Olddocument = XDocument.Load(AppDomain.CurrentDomain.BaseDirectory + "AutoUpdater_Back.xml");
                    //获取到XML的根元素进行操作
                    XElement Oldroot = Olddocument.Root;
                    XElement Oldele = Oldroot.Element("UpdateInfo");
                    //获取旧更新时间标签的值
                    XElement OldUpdateTime = Oldele.Element("UpdateTime");
                    //获取旧版本号标签的值
                    XElement OldVersion = Oldele.Element("Version");
                    //获取最新xml文件更新时间以及更新版本
                    XDocument Newdocument = XDocument.Load(AppDomain.CurrentDomain.BaseDirectory + "AutoUpdater.xml");
                    //获取到XML的根元素进行操作
                    XElement Newroot = Newdocument.Root;
                    XElement Newele = Newroot.Element("UpdateInfo");
                    //获取旧更新时间标签的值
                    XElement NewUpdateTime = Newele.Element("UpdateTime");
                    //获取旧版本号标签的值
                    XElement NewVersion = Newele.Element("Version");
                    if (NewUpdateTime != OldUpdateTime || NewVersion != OldVersion)
                    {
                        //获取需要更新的文件列表
                        XElement NewUpList = Newroot.Element("UpdateList");
                        IEnumerable<XElement> UpList = NewUpList.Elements();
                        foreach (XElement item in UpList)
                        {
                            updatelist.Add(item.Value);
                        }
                        //获取需要删除的文件列表
                        XElement NewDelList = Newroot.Element("DeleteList");
                        IEnumerable<XElement> DelList = NewDelList.Elements();
                        foreach (XElement item in DelList)
                        {
                            deletelist.Add(item.Value);
                        }
                    }
                    #endregion

                    #region 循环获取更新文件
                    for (int i = 0; i < updatelist.Count; i++)
                    {
                        //发送链接成功提示
                        byte[] FileName = Encoding.UTF8.GetBytes(updatelist[i]);
                        byte[] SendFileName = new byte[FileName.Length + 1];//加一位标识用于表示是文字消息还是文件
                        SendFileName[0] = 0; // 用来表示发送的是消息数据
                        Buffer.BlockCopy(FileName, 0, SendFileName, 1, FileName.Length);
                        socketClient.Send(SendFileName);
                        //获取文件
                        string FilePath = Application.StartupPath + "\\WebFile";
                        byte[] bufferByFile = new byte[1024 * 1024 * 50];
                        int lenghtByFile = socketClient.Receive(bufferByFile);
                        if (bufferByFile[0] == 1)
                        {
                            using (FileStream fs = new FileStream(FilePath + "\\" + updatelist[i], FileMode.Create))
                            {
                                fs.Write(bufferByFile, 1, lenghtByFile - 1);
                            }
                            TxtReceiveAddContent("文件接收成功:" + updatelist[i]);
                        }
                    }
                    #endregion

                    #region 循环删除指定文件
                    for (int i = 0; i < deletelist.Count; i++)
                    {
                        try
                        {
                            string path = AppDomain.CurrentDomain.BaseDirectory + "\\WebFile\\" + deletelist[i];
                            File.Delete(path);
                            TxtReceiveAddContent("删除文件[" + deletelist[i] + "]成功");
                        }
                        catch (Exception)
                        {
                            TxtReceiveAddContent("删除文件[" + deletelist[i] + "]失败");
                            continue;
                        }
                    }
                    #endregion
                }
                catch (Exception ex)
                {
                    File.Move(Newpath, Oldpath);//连接失败,还原文件名
                    MessageBox.Show(ex.ToString());
                    throw;
                }

调试在客户端进循环的时候服务端侦听不到了
刚接触socket,多谢大佬们解答

c#

1个回答

服务端开启线程,监听某端口,这里没问题。

SendFileFuncssss方法的while里应该再开子线程,这个子线程不断可以保证一个客户端前后收2次,且支持多个客户端用多个线程,互不影响

参考https://www.cnblogs.com/erictanghu/p/3760944.html

你看server端

dong19980903
共白头 已采纳,感谢大佬,是这样完成的多文件多客户端连接传输,现在又遇到一个问题,多文件容易丢包,尝试了跟你给的参考里类似的方法分包,但是循环发送的时候会出现文件占用,这样还是只能一个客户端传输文件,然后又尝试先一次性获取到所有文件的信息,关闭文件流连接之后再分多次发送,这样还是没办法多客户端同时传输。大概定位到是while循环的问题,暂时没思路继续了。大佬有类似的经验分享嘛?感谢!
7 个月之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐