.NET平台下C# socket通信(下)

这边一起来分析一下多线程的代码,大家也可以在上一篇文章附带的Demo进行尝试。

我们点击启动服务按钮,服务器:

      // 创建负责监听的套接字,注意其中的参数socketWatch  new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);

     // 获得文本框中的IP对象

     IPAddress address = IPAddress.Parse(txtIp.Text.Trim());

       // 创建包含ip和端口号的网络节点对象;

     IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));

    try

    {

     // 将负责监听的套接字绑定到唯一的ip和端口上

      socketWatch.Bind(endPoint);

     }

    catch (SocketException se)

    {

      MessageBox.Show("异常:"+se.Message);

     return;

     }

首先我们创建负责监听的套接字, 在Bind绑定后,我们创建了负责监听的线程。代码如下:

             // 设置监听队列的长度

            socketWatch.Listen(10);

            // 创建负责监听的线程

            threadWatch = new Thread(WatchConnecting);

            threadWatch.IsBackground = true;

            threadWatch.Start();

            ShowMsg("服务器启动监听成功!");

            btnBeginListen.Enabled = false;

 

 

其中 WatchConnecting方法是负责监听新客户端请求的。然后让我们看一下WatchConnecting的代码。

        /// <summary>

        /// 监听客户端请求的方法

        /// </summary>

        void WatchConnecting()

        {

            while (true)  // 持续不断的监听客户端的连接请求

            {

                // 开始监听客户端连接请求,Accept方法会阻断当前的线程

                Socket sokConnection = socketWatch.Accept(); // 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字;

                // 想列表控件中添加客户端的IP信息

                lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString());

                // 将与客户端连接的 套接字 对象添加到集合中

                dict.Add(sokConnection.RemoteEndPoint.ToString(), sokConnection);

                ShowMsg("客户端连接成功!");

                Thread thr = new Thread(RecMsg);

                thr.IsBackground = true;

                thr.Start(sokConnection);

                dictThread.Add(sokConnection.RemoteEndPoint.ToString(), thr);  //  将新建的线程 添加 到线程的集合中去

            }

        }

 

 

这个线程是一直存在的,主要的任务就是监听是否有Client与Server端进行连接,如果连接成功则会另开一个线程”RecMsg”。在该线程中则主要是得到字符数据的处理,包括接受数据以及发送数据。

void RecMsg(object sokConnectionparn)

        {

                Socket sokClient = sokConnectionparn as Socket;

                while (true)

                {

                    // 定义一个2M的缓存区

                    byte[] arrMsgRec = new byte[1024 * 1024 * 2];

                    // 将接受到的数据存入到输入  arrMsgRec中

                    int length = -1;

                    try

                    {

                        length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度

                    }

                    catch (SocketException se)

                    {

                        ShowMsg("异常:" + se.Message);

                        // 从 通信套接字 集合中删除被中断连接的通信套接字;

                        dict.Remove(sokClient.RemoteEndPoint.ToString());

                        // 从通信线程集合中删除被中断连接的通信线程对象;

                        dictThread.Remove(sokClient.RemoteEndPoint.ToString());

                        // 从列表中移除被中断的连接IP

                        lbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());

                        break;

                    }

                    catch (Exception e)

                    {

                        ShowMsg("异常:" + e.Message);

                        // 从 通信套接字 集合中删除被中断连接的通信套接字

                        dict.Remove(sokClient.RemoteEndPoint.ToString());

                        // 从通信线程集合中删除被中断连接的通信线程对象

                        dictThread.Remove(sokClient.RemoteEndPoint.ToString());

                        // 从列表中移除被中断的连接IP

                        lbOnline.Items.Remove(sokClient.RemoteEndPoint.ToString());

                        break;

                    }

                    if (arrMsgRec[0] == 0)  // 表示接收到的是数据

                    {

                        string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec,1, length-1);// 将接受到的字节数据转化成字符串

                        ShowMsg(strMsg);

                    }

                    if (arrMsgRec[0] == 1) // 表示接收到的是文件

                    {

                            SaveFileDialog sfd = new SaveFileDialog();

                          

                            if (sfd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)

                            {// 在上边的 sfd.ShowDialog() 的括号里边一定要加上 this 否则就不会弹出 另存为 的对话框,而弹出的是本类的其他窗口,,这个一定要注意!!!【解释:加了this的sfd.ShowDialog(this),“另存为”窗口的指针才能被SaveFileDialog的对象调用,若不加thisSaveFileDialog 的对象调用的是本类的其他窗口了,当然不弹出“另存为”窗口。】

                              

                                string fileSavePath = sfd.FileName;// 获得文件保存的路径

                                // 创建文件流,然后根据路径创建文件

                                using (FileStream fs = new FileStream(fileSavePath, FileMode.Create))

                                {

                                    fs.Write(arrMsgRec, 1, length - 1);

                                    ShowMsg("文件保存成功:" + fileSavePath);

                                }

                            }

                        }

                }    

        }

 

 

其实这就是建立多线程TCP通信的主要过程,这里值得注意的就是其实监听线程监听的一直都是一个固定的端口,在应用层如果建立建立连接了,则连接不会使用监听的端口号,而会使用另一个空闲的端口号,这样才能保证一直连接监听一直使用一个固定端口号,从而使得连接也变得更加容易。Demo有数据交换的,也有类似于通信的,大家都可以参考。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值