zoukankan      html  css  js  c++  java
  • .NET基础示例系列之二:Socket

    以下示例程序实现简单的Socket通信,可以开多个客户端。本机测试通过,未做联机测试。

    Server

    using System.Net;

    using System.Net.Sockets;

    using System.Threading;

    using System.Collections;

     

    namespace MySocketServer1

    {

        public partial class Form1 : Form

        {

            private IPAddress serverIP = IPAddress.Parse("127.0.0.1");//以本机作测试

            private IPEndPoint serverFullAddr;//完整终端地址

            private Socket sock;

            private System.Timers.Timer myTimer;

            private ArrayList alSock;//当建立了多个连接时用于保存连接

     

            public Form1()

            {

                InitializeComponent();

            }

     

            private void btStart_Click(object sender, EventArgs e)

            {

                serverFullAddr = new IPEndPoint(serverIP, 1000);//取端口号1000

    //构造Socket对象,套接字类型为“流套接字”,指定五元组中的协议元

                sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream,

    ProtocolType.Tcp);

    //指定五元组中的本地二元,即本地主机地址和端口号

                sock.Bind(serverFullAddr);

    //监听是否有连接传入,指定挂起的连接队列的最大值为20

                sock.Listen(20);

     

                alSock = new ArrayList();

     

    //构造定时器,时间间隙为1秒,即每隔一秒执行一次accept()方法,以获取连接请求队列中//第一个挂起的连接请求

                myTimer =new System.Timers.Timer(1000);

                myTimer.Elapsed +=new System.Timers.ElapsedEventHandler(myTimer_Elapsed);

                myTimer.Enabled = true;

            }

     

            private void myTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)

            {

                myTimer.Enabled = false;

    //执行accept(),当挂起队列为空时将阻塞本线程,同时由于上一语句,定时器将停止,直//至有连接传入

                Socket acceptSock = sock.Accept();

    //accept()产生的Socket对象存入ArrayList

                alSock.Add(acceptSock);

    // 构造Threading.Timer对象,这将导致程序另启线程。线程将执行回调函数,该委托限制//函数参数须为object型。Threading.Timer构造器的第二个参数即传入回调函数的参数;第//三个参数指定调用回调函数之前的延时,取0则立即启动;最后一个参数指定调用回调函数//的时间间隔,取0则只执行一次。

                System.Threading.Timer ti = new System.Threading.Timer(new

    TimerCallback(ReceiveMsg), acceptSock, 0, 0);

                myTimer.Enabled = true;

            }

     

            private void ReceiveMsg(object obj)

            {

                Socket acceptSock = (Socket)obj;

                try

                {

                    while (true)

                    {

                        byte[] byteArray = new byte[100];

                        acceptSock.Receive(byteArray);//接收数据

    //将字节数组转成字符串

                        string strRec = System.Text.Encoding.UTF8.GetString(byteArray);

                        if (this.rtbReceive.InvokeRequired)

                        {

                            this.rtbReceive.Invoke(new EventHandler(this.ChangeRickTextBox), new

    object[] { strRec, EventArgs.Empty });

                        }

                    }

                }

                catch(Exception ex)

                {

                    acceptSock.Close();

                    MessageBox.Show("S:Receive Message Error"+ex.Message);

                }

            }

     

            private void ChangeRickTextBox(object obj,EventArgs e)

            {

                string s = System.Convert.ToString(obj);

                this.rtbReceive.AppendText(s + Environment.NewLine);

            }

     

            private void btSend_Click(object sender, EventArgs e)

            {

                Socket sc=null;

                byte[] byteSend =

    System.Text.Encoding.UTF8.GetBytes(this.tbSend.Text.ToCharArray());

                try

                {

    //同时存在若干个客户端连接时,在textBox1中输入要发送的是哪个连接

                    int index = int.Parse(this.textBox1.Text.Trim());

                    sc = (Socket)alSock[index - 1];

    //发送数据

                    sc.Send(byteSend);

                }

                catch(Exception ex)

                {

    if(sc != null)

    {

                    sc.Close();

    }

                    MessageBox.Show("S:Send Message Error"+ex.Message);

                }

            }

     

            private void btClose_Click(object sender, EventArgs e)

            {

                try

                {

                    Application.Exit();

                }

                catch (Exception ex)

                {

                    MessageBox.Show("S:Close Socket Error" + ex.Message);

                }

            }

        }

    }

    == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==

    Client:

    using System.Net;

    using System.Net.Sockets;

    using System.Threading;

     

    namespace MySocketClient1

    {

        public partial class Form1 : Form

        {

            private IPAddress serverIP = IPAddress.Parse("127.0.0.1");

            private IPEndPoint serverFullAddr;

            private Socket sock;

     

            public Form1()

            {

                InitializeComponent();

            }

     

            private void btConnect_Click(object sender, EventArgs e)

            {

                try

                {

                    serverFullAddr = new IPEndPoint(serverIP, 1000);

                    sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream,

    ProtocolType.Tcp);

                    sock.Connect(serverFullAddr);//建立与远程主机的连接

     

    //启动新线程用于接收数据

                    Thread t = new Thread(new ThreadStart(ReceiveMsg));

                    t.Name = "Receive Message";

    //一个线程或者是后台线程或者是前台线程。后台线程与前台线程类似,区别是后台线//程不会防止进程终止。一旦属于某一进程的所有前台线程都终止,公共语言运行库就//会通过对任何仍然处于活动状态的后台线程调用 Abort 来结束该进程。

                    t.IsBackground = true;

                    t.Start();

                }

                catch(Exception ex)

                {

                    MessageBox.Show(ex.Message);

                }

            }

     

            private void ReceiveMsg()

            {

                try

                {

                    while (true)

                    {

                        byte[] byteRec = new byte[100];

                        this.sock.Receive(byteRec);

                        string strRec = System.Text.Encoding.UTF8.GetString(byteRec);

                        if (this.rtbReceive.InvokeRequired)

                        {

                            this.rtbReceive.Invoke(new EventHandler(ChangeRtb), new object[]

    { strRec, EventArgs.Empty });

                        }

                    }

                }

                catch(Exception ex)

                {

                    MessageBox.Show("Receive Message Error"+ex.Message);

                }

            }

     

            private void ChangeRtb(object obj, EventArgs e)

            {

                string s = System.Convert.ToString(obj);

                this.rtbReceive.AppendText(s + Environment.NewLine);

            }

     

            private void btSend_Click(object sender, EventArgs e)

            {

                byte[] byteSend =

    System.Text.Encoding.UTF8.GetBytes(this.tbSend.Text.ToCharArray());

                try

                {

                    this.sock.Send(byteSend);

                }

                catch

                {

                    MessageBox.Show("Send Message Error");

                }

            }

     

            private void btClose_Click(object sender, EventArgs e)

            {

                try

                {

                    this.sock.Shutdown(SocketShutdown.Receive);

                    this.sock.Close();

                    Application.Exit();

                }

                catch

                {

                    MessageBox.Show("Exit Error");

                }

            }

        }

    }

    不解之处:

    Client端红色标注语句:this.sock.Shutdown(SocketShutdown.Receive),如改成

    this.sock.Shutdown(SocketShutdown.Both);this.sock.Shutdown(SocketShutdown.Send);

    则当点击Cloce按钮时,CPU使用率疯涨到100%,而使用this.sock.Shutdown(SocketShutdown.Receive);

    或不调用Shutdown()方法则没有这个问题。难道客户端不应该用Shutdown()

  • 相关阅读:
    反汇编测试
    《Unix/Linux系统编程》第五章学习笔记
    Linux学习笔记
    团队作业三
    缓冲区溢出
    ch6信号学习笔记
    ch5(定时器和时钟)学习笔记
    团队作业(四)
    团队作业(三)
    ch4学习笔记
  • 原文地址:https://www.cnblogs.com/morvenhuang/p/475707.html
Copyright © 2011-2022 走看看