TcpClient,TcpListener监听服务项目总结

项目大概方案是一个服务器端,多个客户端,服务端监听客户端的请求,回应客户端请求向客户端发送文件,服务端还要控制客户端连接最大数。客户端接收服务器端返回的文件。

一、服务端实现代码

 //连接的用户
        private List<ClientUser> userList = new List<ClientUser>();
        //监听对象
        private TcpListener myListener;
        //服务器端IP地址
        private string localaddr = string.Empty;
        //端口
        private int localport;

/// <summary>
        /// 是否正在监听
        /// </summary>
        public bool IsListen = false;
        /// <summary>
        /// 开始监听
        /// </summary>
        public void StartListener()
        {
            try
            {
                logmsg.Title = "启动监听";
                logmsg.Content = string.Format("启动[{0}:{1}]监听,等待客户端连接请求。", localaddr, localport);
                log.Info(logmsg);
                AddItem(logmsg.Content);

                //IP地址
                IPAddress localAddress = IPAddress.Parse(localaddr);
                myListener = new TcpListener(localAddress, localport);
                myListener.Start(this.maxClientUsers);
                IsListen = true;

                //线程池
                ThreadPool.SetMaxThreads(maxClientUsers, maxClientUsers);
                //创建一个线程监听客户端连接请求
                ThreadStart ts = new ThreadStart(ListenClientConnect);
                Thread myThread = new Thread(ts);
                myThread.Start();
            }
            catch (Exception ex)
            {               
                logmsg.Title = "启动监听出错";
                logmsg.Content = string.Format("启动[{0}:{1}]监听出错,", localaddr, localport) + string.Format("错误:{0}", ex.Message);
                log.Error(logmsg);
                AddItem(logmsg.Content);
                IsListen = false;
            }
        }
        /// <summary>
        /// 关闭监听
        /// </summary>
        public void CloseListener()
        {
            try
            {
                myListener.Stop();

                IsListen =false;
                AddItem(string.Format("关闭[{0}:{1}]监听。", localaddr, localport));

                logmsg.Title = "关闭监听";
                logmsg.Content = string.Format("关闭[{0}:{1}]监听。", localaddr, localport);
                log.Info(logmsg);
            }
            catch (Exception ex)
            {
                IsListen = true;

                logmsg.Title = "关闭监听出错";
                logmsg.Content = string.Format("关闭[{0}:{1}]监听出错", localaddr, localport) + string.Format("错误:{0}", ex.Message);
                log.Error(logmsg);
                AddItem(logmsg.Content);
            }
        }
        /// <summary>
        /// 接收客户端连接
        /// </summary>
        private void ListenClientConnect()
        {
            while (true)
            {
                TcpClient newClient = null;
                try
                {
                    //等待用户进入
                    newClient = myListener.AcceptTcpClient();
                }
                catch (Exception ex)
                {
                    //当单击“停止监听”或者退出此窗体时AcceptTcpClient()会产生异常
                    //因此可以利用此异常退出循环                    
                    break;
                }
                if (newClient != null)
                {
                    string text = string.Empty;
                    string sendString = string.Empty;

                    //接收消息,超时时间
                    //newClient.ReceiveTimeout = 1 * 60 * 1000;
                    ClientUser user = new ClientUser(newClient);
                    user.userName = newClient.Client.RemoteEndPoint.ToString();
                    string[] _NewEndPointArr = user.userName.Split(':');

                    foreach (ClientUser item in userList)
                    {
                        string[] _OldEndPointArr = item.userName.Split(':');
                        if (_OldEndPointArr[0].Trim().Equals(_NewEndPointArr[0].Trim()) && _OldEndPointArr[1].Trim().Equals(_NewEndPointArr[1].Trim()))
                        {
                            item.client.Close();
                            logmsg.Title = logmsg.Content = string.Format("[{0}]关闭上次连接。", item.userName);
                            log.Info(logmsg);
                        }
                    }

                    userList.Add(user);
                    Count(userList.Count);
                    //线程池
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveData), user);
                    //通知客户端连接成功
                    SendTextToOne(user, "0|ok|连接成功", "", "");

                }
                else
                {
                    //连接失败
                    AddItem("接收客户端连接失败。");
                }
            }
        }
        /// <summary>
        /// 接收、处理客户端信息,每个客户1个线程,参数用户区分客户端
        /// </summary>
        /// <param name="obj"></param>
        private void ReceiveData(object obj)
        {
            ClientUser user = (ClientUser)obj;
            TcpClient client = user.client;
            int timeOut=30 * 1000;
            client.ReceiveTimeout = timeOut;
            string userNameStr = user.userName;
            //是否正常退出接收线程
            bool normalExit = false;
            //用于控制是否退出循环
            bool exitWhile = false;
            string text = string.Empty;
            string factorycodeStr = string.Empty;
            string factoryName = string.Empty;
            FactoryInfo model = new FactoryInfo();
            int sleepTime = 0;
            string nomalText = "";
            while (exitWhile == false)
            {
                #region 接收客户端信息
                string receiveString = string.Empty;
                string sendString = string.Empty;//发送信息
                try
                {
                    if (user.netStream.DataAvailable)
                    {
                        receiveString = user.sr.ReadLine();
                        if (userList.Count > maxClientUsers && !string.IsNullOrEmpty(receiveString))
                        {
                            #region 超过最大连接数
                            //向客户端返回信息
                            //格式:指令序号|状态State|消息Message|备用数据项
                            text = string.Format("服务器已达到最大连接数[{0}]", maxClientUsers);
                            sendString = "2|error|" + text + ",请稍后重新请求";
                            SendTextToOne(user, sendString, factorycodeStr, factoryName); 

                            text += string.Format(",拒绝[{0}]连接请求。", user.userName);
                            AddItem(text);
                            #endregion
                            nomalText = "超过最大连接数" + maxClientUsers;
                            normalExit = true;
                            break;
                        }
                    }
                    else
                    {
                        Thread.Sleep(3000);
                        sleepTime += 1;
                        if (sleepTime>0 && sleepTime <= 10)
                        {
                            continue;
                        }
                        else
                        {
                            break;//一直接收不到消息就退出
                        }
                    }
                }
                catch (Exception ex)
                {
                    //该客户底层套接字不存在时会出现异常
                    //AddItem(string.Format("接收{1}数据失败,原因:{0}", ex.Message, user.userName));

                    logmsg.Title = "接收客户端信息出错,";
                    logmsg.Content = "接收" + user.userName + "信息出错,原因:" + ex.ToString();
                    log.Error(logmsg);

                    break;//退出循环
                }
                #endregion
                //已接收到消息,重置等待次数
                sleepTime = 0;
                #region 检查TcpClient 对象是否关闭
                //TcpClient 对象将套接字进行了封装,如果TcpClient对象关闭了,
                //但是底层套接字未关闭,并不产生异常,但是读取的结果为 null
                if (string.IsNullOrEmpty(receiveString))
                {
                    if (normalExit == false)
                    {
                        //如果停止了监听,Connected 为 false
                        if (!client.Connected)
                        {
                            AddItem(string.Format("与[{0}]失去联系,已停止接收该客户端信息", client.Client.RemoteEndPoint));
                            logmsg.Title = "与客户端失去联系";
                            logmsg.Content = string.Format("已停止接收[{0}]客户端信息。", client.Client.RemoteEndPoint);
                            log.Warn(logmsg);
                        }
                    }
                    //退出循环
                    break;
                }
                else if (!receiveString.Contains("|"))
                {
                    sendString = "请求拒绝,原因:请求信息格式错误";
                    SendTextToOne(user, sendString, factorycodeStr, factoryName);

                    logmsg.Title = "拒绝客户端请求";
                    logmsg.Content = string.Format("拒绝来自[{0}]的请求,原因:请求信息[{1}]格式错误。", userNameStr, receiveString);
                    //log.Warn(logmsg);

                    AddItem(logmsg.Content);

                    break;//退出循环
                }
                #endregion

                #region 对客户端信息进行分割
                text = string.Format("接收[{0}]的信息:{1}。", userNameStr, receiveString);
                AddItem(text);
                logmsg.Title = "接收到客户端信息";
                logmsg.Content = text;
                log.Info(logmsg);
                string[] splitString = receiveString.Split('|');
                string command = splitString[0];//请求指令
                #endregion

                #region  处理接收到的消息
                switch (command.ToString())
                {
                    case "1":
                        //向客户端发送连接成功消息
                        break;
                    case "3":
                        //向客户端发送文件,在获取文件时要避免重复发送某一个文件,需要对代码加锁
                        break;
                    
                }
        }



//获取一个文件名,文件大小等参数
 private string GetAPacketFullFileName(参数省略)
        {
            string fullFileNameBackup = string.Empty;
            //加锁  防止文件重发
            lock (obj)
            {
                //获取文件部分,省略...
                //要保证文件是不重名的,获取一个文件名后,要记录文件名已发送过
            }
            return fullFileName;

        }

二、客户端请求和接收消息实现

                 client = new TcpClient();
                //client.ReceiveTimeout = 1 * 60 * 1000;
                try
                {
                    client.Connect(IPAddress.Parse(serverIP), port);
                    
                        //获取网络流
                    NetworkStream netStream = client.GetStream();
                    //hanym 添加网络流判断
                     if (netStream != null)
                     {
                         //添加读取数据缓存大小设置
                         sr = new StreamReader(netStream, System.Text.Encoding.UTF8, true, 1024*100);
                         sw = new StreamWriter(netStream, System.Text.Encoding.UTF8);
                         //向线程池添加接受消息任务
                         //ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveData), DateTime.Now.ToString());
                         ReceiveData(DateTime.Now.ToString());
                     }
                     else
                     {
                         logmsg.Title = "[" + factorycode + "]与服务器连接失败,获取网络流失败";
                         logmsg.Content = string.Format("与服务器{0}连接失败," , serverIP + ":" + port); 
                         log.Error(logmsg);
                         return;
                     }
                }
                catch (Exception ex)
                {
                    logmsg.Title = "["+factorycode+"]与服务器建立连接出错";
                    logmsg.Content = string.Format("与服务器{0}连接出错,错误:"+ex.ToString(), serverIP + ":" + port);
                    log.Error(logmsg);
                    AddItem(string.Format("与服务器{0}连接失败,错误:"+ex.Message, serverIP + ":" + port)) ;
                    return;
                }

      /// <summary>
        /// 接收服务器端信息
        /// </summary>
        /// <param name="FileName"></param>
        /// <param name="errmessage"></param>
        private void ReceiveData(object obj)
        {
            FileSize = 0;
            //FileName = string.Empty;
            string errmessage = string.Empty;
            bool exitWhile = false;
            while (exitWhile == false)
            {
                string receiveString = string.Empty;

                #region 接收消息
                try
                {
                    if (client.Available <= 0)
                    {
                        continue;
                    }
                    {
                        receiveString = sr.ReadLine();
                    }
                }
                catch (Exception ex)
                {
                    logmsg.Title = "接收服务器端信息失败";
                    logmsg.Content = "原因:" + ex.Message;
                    log.Error(logmsg);

                    normalExit = true;
                    break;
                }
                #endregion

                #region  验证接收到的消息
                if (string.IsNullOrEmpty(receiveString))
                {
                    if (normalExit == false)
                    {
                        errmessage = "与服务器端失去联系。";

                        AddItem("与服务器端失去联系。");
                    }
                    normalExit = true;
                    //结束线程
                    break;
                }               
                #endregion

                string[] splitString = receiveString.Split('|');
                string command = splitString[0].ToLower();
                int intcmd=-1;
                if (int.TryParse(command, out intcmd))
                {
                    logmsg.Title = "接收服务器端信息";
                    logmsg.Content = "信息:" + receiveString;
                    log.Info(logmsg);
                }
                string sendMsg = string.Empty;
                #region  处理接收的消息
                switch (command)
                {
                    case "0":
                        #region  接收到服务器连接结果信息, 如果连接成功向服务器请求
                        if (splitString[1] == "error")
                        {
                            if (splitString.Length > 2)
                            {
                                errmessage = "向服务器端发送连接请求失败,原因:" + splitString[2].ToString();
                            }
                            else
                            {
                                errmessage = "向服务器端发送连接请求失败。";
                            }
                            AddItem(errmessage);

                            exitWhile = true;
                            break;
                        }
                       
                        sendMsg = "1|参数1|参数2|参数3";
                        SendToServer(sendMsg);//向服务器端发送文件请求
                        #endregion
                        break;

                    case "4":
                        #region 接收服务端发送文件参数消息
                        if (splitString[1] == "error")
                        {//如果请求的文件在服务器里没有了,则退出。
                            errmessage = splitString[2];
                            break;
                        }
                        string filefullname = string.Empty;//全名称(包含路径)
                        string filename = splitString[3];//文件名
                        string filesize = splitString[4];//文件大小

                        #endregion

                        #region 开始接收文件
                        try
                        {
                            NetworkStream ns = client.GetStream();
                            byte[] bufferRec = new byte[1024 * 1024 * 2];
                            if (!Directory.Exists(path))
                            {
                                Directory.CreateDirectory(path);
                            }
                            filefullname = path + @"\" + filename;
                            FileStream fs = File.Open(filefullname, FileMode.OpenOrCreate, FileAccess.Write);
                            int Len = 0;
                            while (Len < int.Parse(filesize))
                            {
                                int readLen = ns.Read(bufferRec, 0, bufferRec.Length);
                                fs.Write(bufferRec, 0, readLen);
                                Len += readLen;
                            }
                            fs.Dispose();
                            fs.Close();
                            /*MemoryStream ms = new System.IO.MemoryStream();
                            byte[] resBytes = new byte[1024 * 1024 * 2];//定义一个2MB缓存区
                            int resSize;
                            do
                            {
                                resSize = ns.Read(resBytes, 0, resBytes.Length);
                                if (resSize == 0) break;
                                ms.Write(resBytes, 0, resSize);
                            } while (ns.DataAvailable);

                            if (ms.Length > 0)
                            {
                                if (!Directory.Exists(path))
                                {
                                    Directory.CreateDirectory(path);
                                }
                                filefullname = path + @"\" + filename;
                                FileStream fs = File.Open(filefullname, FileMode.OpenOrCreate, FileAccess.Write);                                   
                                fs.Write(ms.ToArray(), 0, (int)ms.Length);
                                fs.Flush();
                                fs.Close(); //关闭文件流 
                            }
                            */

                            if (File.Exists(filefullname))
                            {
                                FileInfo info = new FileInfo(filefullname);
                                FileSize = info.Length;
                            }
                            AddItem("发送大小:" + filesize + "实际接收大小:" + FileSize);
                            logmsg.Title = "[" + FactoryCode + "]接收文件大小信息";
                            logmsg.Content = "发送大小:" + filesize + ",收到大小:" + FileSize + ",文件:" + filename;
                            if (FileSize < long.Parse(filesize))
                            {
                                logmsg.Title = "[" + FactoryCode + "]接收文件大小出错";
                                log.Error(logmsg);
                            }
                            else
                            {
                                log.Info(logmsg);
                            }
                            #region 文件接收完成后向服务器端发送指令,通知接收完成。
                            SendToServer("5|ok|文件接收成功);
                            #endregion
                        }
                        catch (Exception ex)
                        {
                            logmsg.Title = "[" + FactoryCode + "]接收服务器文件出错";
                            logmsg.Content = "错误:" + ex.ToString();
                            log.Error(logmsg);
                            SendToServer("5|error|文件接收失败);
                        }
                        #endregion

                        Thread.Sleep(3000);
                        exitWhile = true;//文件接收结束,当前线程不再接收消息
                        break;
                }//end switch
                #endregion
            }//end while
        }
        /// <summary>
        /// 向服务器发送数据
        /// </summary>
        /// <param name="str">信息内容</param>
        private void SendToServer(string str)
        {
            try
            {
                sw.WriteLine(str);
                sw.Flush();
            }
            catch (Exception ex)
            {
                logmsg.Title =向服务器发送信息出错";
                logmsg.Content = "信息:" + str + "原因:" + ex.Message;
                log.Error(logmsg);
            }
        }

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C#中的TcpClientTcpListener是用于创建和处理TCP连接的类。TcpClient用于创建TCP客户端,而TcpListener用于创建TCP服务器。 TcpClient类用于在客户端与服务器之间建立连接。可以通过TcpClient对象的构造函数创建实例,并使用Connect方法连接到指定的服务器和端口。一旦连接建立,就可以使用NetworkStream来发送和接收数据。 以下是一个简单的示例代码,演示了如何使用TcpClient发送数据: ```csharp using System; using System.Net.Sockets; class Program { static void Main() { try { TcpClient client = new TcpClient("127.0.0.1", 8080); NetworkStream stream = client.GetStream(); string message = "Hello, Server!"; byte[] data = System.Text.Encoding.ASCII.GetBytes(message); stream.Write(data, 0, data.Length); Console.WriteLine("Message sent to the server."); stream.Close(); client.Close(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } } ``` TcpListener类用于创建TCP服务器,它监听指定的端口,并等待客户端的连接请求。可以使用AcceptTcpClient方法来接受客户端连接,并返回一个TcpClient对象以进行数据传输。 以下是一个简单的示例代码,演示了如何使用TcpListener接收数据: ```csharp using System; using System.Net; using System.Net.Sockets; class Program { static void Main() { TcpListener server = null; try { // 设置监听IP和端口 IPAddress ipAddress = IPAddress.Parse("127.0.0.1"); int port = 8080; server = new TcpListener(ipAddress, port); // 开始监听 server.Start(); Console.WriteLine("Server started. Waiting for clients..."); // 接受客户端连接 TcpClient client = server.AcceptTcpClient(); // 获取客户端的网络流 NetworkStream stream = client.GetStream(); byte[] data = new byte[1024]; // 读取客户端发送的数据 int bytesRead = stream.Read(data, 0, data.Length); string message = System.Text.Encoding.ASCII.GetString(data,0, bytesRead); Console.WriteLine("Received message: " + message); stream.Close(); client.Close(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } finally { if (server != null) server.Stop(); } } } ``` 这些是TcpClientTcpListener的基本用法示例。你可以根据你的需求进行进一步的开发和处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值