zoukankan      html  css  js  c++  java
  • 三 C# Socket通信 窗体控件与多线程

      在实际项目中,涉及套接字的都必须使用多线程,当接收端所接收到的消息需要显示到窗体控件上时,必须使用委托。这是因为窗体控件在窗体初始化时便被声明,即控件在主线程中被定义;而窗体控件具有一个属性,那就是:控件不具备跨线程的能力。因此,套接字编程中凡是涉及到窗体控件时,都必须调用控件的异步方法。下面举例说明:

      1 发送端(或者客户端)程序代码:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;

    using System.Net;
    using System.Net.Sockets;
    using System.Threading;

    namespace DelTest
    {
        
    public partial class Form1 : Form
        
    {
            
            
    private void Form1_Load(object sender, EventArgs e)
            
    {
            }

            
            
    private void button1_Click(object sender, EventArgs e)
            
    {
                IPAddress ipa 
    = IPAddress.Parse("127.0.0.2");
                IPEndPoint ipe 
    = new IPEndPoint(ipa, 2000);
                Socket client 
    = new Socket(
                    AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                
    try
                
    {
                    client.Connect(ipe);
                    
    if (client.Connected)
                    
    {
                        
    byte[] sends = Encoding.Unicode.GetBytes(this.textBox1.Text);
                        client.Send(sends);
                    }

                }

                
    catch (Exception ee)
                
    {}
            }


            
    /// <summary>
            
    /// 与远程进行连接
            
    /// </summary>
            
    /// <param name="ip">远程IP地址</param>
            
    /// <param name="port">远程侦听端口</param>
            
    /// <returns></returns>

            private Socket Connect(string ip, int port)
            
    {
                IPAddress ipa 
    = IPAddress.Parse(ip);
                IPEndPoint ipe 
    = new IPEndPoint(ipa, port);
                Socket sender 
    = new Socket(
                    AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                
    try
                
    {
                    sender.Connect(ipe);
                }

                
    catch (SocketException se)
                
    {
                    
    return null;
                }

                
    return sender;
            }


            
    public Form1()
            
    {
                InitializeComponent();
            }

        }

    }

      发送端的界面很简单,如下图图1所示:

      

                            图1                          图2

      2 接收端(或者服务端)程序代码(界面如上图图2所示):

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;

    using System.Net;
    using System.Net.Sockets;
    using System.Threading;

    namespace SocketRec
    {
        
    public partial class Form1 : Form
        
    {
            
    delegate void ThreadMethod(object obj);
            ThreadMethod _tm 
    = null;

            
    private Socket _listener = null;
            
    private string _localIP = null;

            

            
    private void Form1_Load(object sender, EventArgs e)
            
    {
                _tm 
    = Show;

                _localIP 
    = Dns.GetHostAddresses(Dns.GetHostName())[0].ToString();
                _listener 
    = new Socket(
                    AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                _listener.Bind(
    new IPEndPoint(IPAddress.Parse(_localIP), 2000));
                _listener.Listen(
    50);

                Thread thread 
    = new Thread(new ThreadStart(Receive));
                thread.IsBackground 
    = true;
                thread.Start();
            }


            
    private void Receive()
            
    {
                
    try
                
    {
                    Socket accept 
    = _listener.Accept();
                    
    while (true)
                    
    {
                        
    byte[] rec = new byte[4900];
                        accept.Receive(rec);

                        
    string recStr = Encoding.Unicode.GetString(rec);
                        _tm(recStr);
                    }

                }

                
    catch (Exception ee)
                
    {

                }

            }

            
    /// <summary>
            
    /// 委托实例
            
    /// </summary>
            
    /// <param name="obj">在多线程间传递数据</param>

            private void Show(object obj)
            
    {
                
    if (this.richTextBox1.InvokeRequired)
                
    {
                    
    /**由于windows窗体及其他控件不具备跨线程的能力,
                     * 所以这里必须调用控件的异步委托方法
                     
    */

                    
    this.richTextBox1.Invoke(new EventHandler(ControlDelegate),
                        
    new object[] { obj, EventArgs.Empty });
                }

            }

            
    //控件调用的方法
            private void ControlDelegate(object sender, EventArgs e)
            
    {
                
    this.richTextBox1.AppendText(sender.ToString());
            }


            
    public Form1()
            
    {
                InitializeComponent();
            }

        }

    }

      3 总结

      凡是涉及窗体控件的套接字编程,当控件需要显示侦听到的套接字时,必须使用控件的Invoke(EventHandler void, object obj)异步调用方法,否则程序肯定报错。通常在套接字编程中使用到的控件有:TextBox、RichTextBox、PictureBox……

      在一个大型项目中,套接字的侦听一般被封装在最底层,而控件的显示则封装在最上层,这中间可能隔了若干层,那么侦听到的套接字流只能通过委托来一层一层地传递数据,因为委托的功能很强大,可以跨线程。委托的签名只需满足void delegateMethod(object obj)即可,即:使用obj这个参数来传递数据。

      当然,在真正的项目中,套接字编程基本都会使用多线程技术,如果连接的终端很多,还会使用异步技术,下面的几篇文章将会介绍一下C#中的线程使用方法以及多线程如何共享数据和如何让一个方法在多线程中同步。最后再帖上项目中的主要代码,以做留念和参考。

  • 相关阅读:
    Linux centosVMware Linux监控平台介绍、zabbix监控介绍、安装zabbix、忘记Admin密码如何做
    Linux centosVMware Linux集群架构LVS DR模式搭建、keepalived + LVS
    Linux centosVMware 集群介绍、keepalived介绍、用keepalived配置高可用集群
    Linux centosVMware 配置Tomcat监听80端口、配置Tomcat虚拟主机、Tomcat日志
    Linux centosVMware Tomcat介绍、安装jdk、安装Tomcat
    Linux centosVMware xshell使用xftp传输文件、使用pure-ftpd搭建ftp服务
    Linux centosVMware NFS介绍、NFS服务端安装配置、NFS配置选项
    Linux centosVMware NFS exportfs命令、NFS客户端问题、FTP介绍、使用vsftpd搭建ftp
    Linux centosVMware mysql用户管理、常用sql语句、mysql数据库备份恢复
    Linux centosVMware MySQL常用操作设置更改root密码、连接mysql、mysql常用命令
  • 原文地址:https://www.cnblogs.com/pricks/p/1596122.html
Copyright © 2011-2022 走看看