TCP通信之Socket

来源:互联网 发布:跳过windows update 编辑:程序博客网 时间:2024/04/29 01:50

一、Socket介绍

程序员可以通过socket来发送和接收网络上的数据。

C#中,MS为我们提供了 System.Net.Sockets 命名空间,里面包含了Socket类。

 

二、访问网络

要想访问网络,还得有些基本的条件:

a. 要确定本机的IP和端口,socket只有与某一IP和端口绑定,才能发挥强大的威力。

b. 得有协议吧(否则谁认得你这发送到网络的是什么呀)。TCP & UDP

 

 

  如果具备了基本的条件,就可以开始用它们访问网络了。来看看步骤吧:

 

       a. 建立一个套接字,绑定本机的IP和端口

        套件字: 就是网络通信的接口,一个IP地址 然后 接上冒号和端口。相当于家门前的邮箱。

 

       c. 如果是TCP,因为是面向连接的,所以要利用ListenO()方法来监听网络上是否有人给自己发东西;如果是UDP,因为是无连接的,所以来者不拒。

 

       d. TCP情况下,如果监听到一个连接,就可以使用accept来接收这个连接,然后就可以利用Send/Receive来执行操作了。而UDP,则不需要accept, 直接使用SendTo/ReceiveFrom来执行操作。(看清楚哦,和TCP的执行方法有区别,因为UDP不需要建立连接,所以在发送前并不知道对方的IP和端口,因此需要指定一个发送的节点才能进行正常的发送和接收)

       e. 如果你不想继续发送和接收了,就不要浪费资源了。能close的就close吧。


三、流程图



代码:

       /// <summary>        /// 设计器支持所需的方法 - 不要        /// 使用代码编辑器修改此方法的内容。        /// </summary>        private void InitializeComponent()        {            this.groupBox1 = new System.Windows.Forms.GroupBox();            this.radioButton2 = new System.Windows.Forms.RadioButton();            this.radioButton1 = new System.Windows.Forms.RadioButton();            this.label1 = new System.Windows.Forms.Label();            this.ServerIP = new System.Windows.Forms.TextBox();            this.label2 = new System.Windows.Forms.Label();            this.ServerPort = new System.Windows.Forms.TextBox();            this.label3 = new System.Windows.Forms.Label();            this.ClientIp = new System.Windows.Forms.ComboBox();            this.BtnStartListener = new System.Windows.Forms.Button();            this.BtnStopListener = new System.Windows.Forms.Button();            this.label4 = new System.Windows.Forms.Label();            this.TextRead = new System.Windows.Forms.TextBox();            this.label5 = new System.Windows.Forms.Label();            this.TextWrite = new System.Windows.Forms.TextBox();            this.CheckBoxRead = new System.Windows.Forms.CheckBox();            this.BtnReadClear = new System.Windows.Forms.Button();            this.CheckBoxWrite = new System.Windows.Forms.CheckBox();            this.BtnWriteClear = new System.Windows.Forms.Button();            this.BtnWrite = new System.Windows.Forms.Button();            this.groupBox1.SuspendLayout();            this.SuspendLayout();            //             // groupBox1            //             this.groupBox1.Controls.Add(this.radioButton2);            this.groupBox1.Controls.Add(this.radioButton1);            this.groupBox1.Location = new System.Drawing.Point(12, 12);            this.groupBox1.Name = "groupBox1";            this.groupBox1.Size = new System.Drawing.Size(175, 53);            this.groupBox1.TabIndex = 0;            this.groupBox1.TabStop = false;            this.groupBox1.Text = "TCP协议类型";            //             // radioButton2            //             this.radioButton2.AutoSize = true;            this.radioButton2.Location = new System.Drawing.Point(95, 20);            this.radioButton2.Name = "radioButton2";            this.radioButton2.Size = new System.Drawing.Size(59, 16);            this.radioButton2.TabIndex = 1;            this.radioButton2.Text = "客户端";            this.radioButton2.UseVisualStyleBackColor = true;            //             // radioButton1            //             this.radioButton1.AutoSize = true;            this.radioButton1.Checked = true;            this.radioButton1.Location = new System.Drawing.Point(6, 20);            this.radioButton1.Name = "radioButton1";            this.radioButton1.Size = new System.Drawing.Size(59, 16);            this.radioButton1.TabIndex = 0;            this.radioButton1.TabStop = true;            this.radioButton1.Text = "服务端";            this.radioButton1.UseVisualStyleBackColor = true;            //             // label1            //             this.label1.AutoSize = true;            this.label1.Location = new System.Drawing.Point(210, 12);            this.label1.Name = "label1";            this.label1.Size = new System.Drawing.Size(77, 12);            this.label1.TabIndex = 1;            this.label1.Text = "服务器地址:";            //             // ServerIP            //             this.ServerIP.Location = new System.Drawing.Point(283, 9);            this.ServerIP.Name = "ServerIP";            this.ServerIP.Size = new System.Drawing.Size(142, 21);            this.ServerIP.TabIndex = 2;            //             // label2            //             this.label2.AutoSize = true;            this.label2.Location = new System.Drawing.Point(441, 12);            this.label2.Name = "label2";            this.label2.Size = new System.Drawing.Size(77, 12);            this.label2.TabIndex = 3;            this.label2.Text = "服务器端口:";            //             // ServerPort            //             this.ServerPort.Location = new System.Drawing.Point(515, 9);            this.ServerPort.Name = "ServerPort";            this.ServerPort.Size = new System.Drawing.Size(67, 21);            this.ServerPort.TabIndex = 4;            this.ServerPort.Text = "1234";            //             // label3            //             this.label3.AutoSize = true;            this.label3.Location = new System.Drawing.Point(210, 53);            this.label3.Name = "label3";            this.label3.Size = new System.Drawing.Size(65, 12);            this.label3.TabIndex = 5;            this.label3.Text = "在线客户:";            //             // ClientIp            //             this.ClientIp.FormattingEnabled = true;            this.ClientIp.Location = new System.Drawing.Point(281, 50);            this.ClientIp.Name = "ClientIp";            this.ClientIp.Size = new System.Drawing.Size(300, 20);            this.ClientIp.TabIndex = 6;            //             // BtnStartListener            //             this.BtnStartListener.Location = new System.Drawing.Point(618, 3);            this.BtnStartListener.Name = "BtnStartListener";            this.BtnStartListener.Size = new System.Drawing.Size(75, 30);            this.BtnStartListener.TabIndex = 7;            this.BtnStartListener.Text = "开始监听";            this.BtnStartListener.UseVisualStyleBackColor = true;            this.BtnStartListener.Click += new System.EventHandler(this.BtnStartListener_Click);            //             // BtnStopListener            //             this.BtnStopListener.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;            this.BtnStopListener.Enabled = false;            this.BtnStopListener.Location = new System.Drawing.Point(618, 45);            this.BtnStopListener.Name = "BtnStopListener";            this.BtnStopListener.Size = new System.Drawing.Size(75, 29);            this.BtnStopListener.TabIndex = 8;            this.BtnStopListener.Text = "停止监听";            this.BtnStopListener.UseVisualStyleBackColor = true;            this.BtnStopListener.Click += new System.EventHandler(this.BtnStopListener_Click);            //             // label4            //             this.label4.AutoSize = true;            this.label4.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));            this.label4.ForeColor = System.Drawing.Color.DarkRed;            this.label4.Location = new System.Drawing.Point(209, 93);            this.label4.Name = "label4";            this.label4.Size = new System.Drawing.Size(127, 28);            this.label4.TabIndex = 9;            this.label4.Text = "接收数据显示窗口\r\n\r\n";            //             // TextRead            //             this.TextRead.Location = new System.Drawing.Point(13, 117);            this.TextRead.Multiline = true;            this.TextRead.Name = "TextRead";            this.TextRead.Size = new System.Drawing.Size(568, 158);            this.TextRead.TabIndex = 10;            //             // label5            //             this.label5.AutoSize = true;            this.label5.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));            this.label5.ForeColor = System.Drawing.Color.DarkRed;            this.label5.Location = new System.Drawing.Point(209, 300);            this.label5.Name = "label5";            this.label5.Size = new System.Drawing.Size(127, 14);            this.label5.TabIndex = 11;            this.label5.Text = "发送数据显示窗口";            //             // TextWrite            //             this.TextWrite.Location = new System.Drawing.Point(13, 329);            this.TextWrite.Multiline = true;            this.TextWrite.Name = "TextWrite";            this.TextWrite.Size = new System.Drawing.Size(568, 158);            this.TextWrite.TabIndex = 12;            //             // CheckBoxRead            //             this.CheckBoxRead.AutoSize = true;            this.CheckBoxRead.Location = new System.Drawing.Point(618, 131);            this.CheckBoxRead.Name = "CheckBoxRead";            this.CheckBoxRead.Size = new System.Drawing.Size(84, 16);            this.CheckBoxRead.TabIndex = 13;            this.CheckBoxRead.Text = "16进制格式";            this.CheckBoxRead.UseVisualStyleBackColor = true;            //             // BtnReadClear            //             this.BtnReadClear.Location = new System.Drawing.Point(618, 168);            this.BtnReadClear.Name = "BtnReadClear";            this.BtnReadClear.Size = new System.Drawing.Size(75, 25);            this.BtnReadClear.TabIndex = 14;            this.BtnReadClear.Text = "清 空";            this.BtnReadClear.UseVisualStyleBackColor = true;            this.BtnReadClear.Click += new System.EventHandler(this.BtnReadClear_Click);            //             // CheckBoxWrite            //             this.CheckBoxWrite.AutoSize = true;            this.CheckBoxWrite.Location = new System.Drawing.Point(618, 351);            this.CheckBoxWrite.Name = "CheckBoxWrite";            this.CheckBoxWrite.Size = new System.Drawing.Size(84, 16);            this.CheckBoxWrite.TabIndex = 16;            this.CheckBoxWrite.Text = "16进制格式";            this.CheckBoxWrite.UseVisualStyleBackColor = true;            //             // BtnWriteClear            //             this.BtnWriteClear.Location = new System.Drawing.Point(618, 383);            this.BtnWriteClear.Name = "BtnWriteClear";            this.BtnWriteClear.Size = new System.Drawing.Size(75, 25);            this.BtnWriteClear.TabIndex = 17;            this.BtnWriteClear.Text = "清 空";            this.BtnWriteClear.UseVisualStyleBackColor = true;            this.BtnWriteClear.Click += new System.EventHandler(this.BtnWriteClear_Click);            //             // BtnWrite            //             this.BtnWrite.Location = new System.Drawing.Point(618, 427);            this.BtnWrite.Name = "BtnWrite";            this.BtnWrite.Size = new System.Drawing.Size(75, 25);            this.BtnWrite.TabIndex = 18;            this.BtnWrite.Text = "发 送";            this.BtnWrite.UseVisualStyleBackColor = true;            this.BtnWrite.Click += new System.EventHandler(this.BtnWrite_Click);            //             // Form1            //             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;            this.ClientSize = new System.Drawing.Size(701, 499);            this.Controls.Add(this.BtnWrite);            this.Controls.Add(this.BtnWriteClear);            this.Controls.Add(this.CheckBoxWrite);            this.Controls.Add(this.BtnReadClear);            this.Controls.Add(this.CheckBoxRead);            this.Controls.Add(this.TextWrite);            this.Controls.Add(this.label5);            this.Controls.Add(this.TextRead);            this.Controls.Add(this.label4);            this.Controls.Add(this.BtnStopListener);            this.Controls.Add(this.BtnStartListener);            this.Controls.Add(this.ClientIp);            this.Controls.Add(this.label3);            this.Controls.Add(this.ServerPort);            this.Controls.Add(this.label2);            this.Controls.Add(this.ServerIP);            this.Controls.Add(this.label1);            this.Controls.Add(this.groupBox1);            this.Name = "Form1";            this.Text = "TCP";            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);            this.groupBox1.ResumeLayout(false);            this.groupBox1.PerformLayout();            this.ResumeLayout(false);            this.PerformLayout();        }        #endregion        private System.Windows.Forms.GroupBox groupBox1;        private System.Windows.Forms.RadioButton radioButton2;        private System.Windows.Forms.RadioButton radioButton1;        private System.Windows.Forms.Label label1;        private System.Windows.Forms.TextBox ServerIP;        private System.Windows.Forms.Label label2;        private System.Windows.Forms.TextBox ServerPort;        private System.Windows.Forms.Label label3;        private System.Windows.Forms.ComboBox ClientIp;        private System.Windows.Forms.Button BtnStartListener;        private System.Windows.Forms.Button BtnStopListener;        private System.Windows.Forms.Label label4;        private System.Windows.Forms.TextBox TextRead;        private System.Windows.Forms.Label label5;        private System.Windows.Forms.TextBox TextWrite;        private System.Windows.Forms.CheckBox CheckBoxRead;        private System.Windows.Forms.Button BtnReadClear;        private System.Windows.Forms.CheckBox CheckBoxWrite;        private System.Windows.Forms.Button BtnWriteClear;        private System.Windows.Forms.Button BtnWrite;

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Net;using System.Net.Sockets;using System.Threading;namespace TCPApplication{    public partial class Form1 : Form    {        /// <summary>        /// 套接字(服务器或客户端)        /// </summary>        Socket newsock;        /// <summary>        /// 当前线程列表(非主线程)        /// </summary>        Dictionary<int, Thread> ThreadList = new Dictionary<int, Thread>();        /// <summary>        /// Tcp协议类型        /// </summary>        string Tcplx = null;        /// <summary>        /// 解码器(可以用于汉字)        /// </summary>        Encoding encoding = Encoding.GetEncoding("GB2312");        /// <summary>        /// 设置缓冲区        /// </summary>        byte[] receiveBytes = new byte[1024];        /// <summary>        /// 接收数据的大小        /// </summary>        int recCount;        /// <summary>        /// 接收的数据        /// </summary>        string data = null;                        //private SynchronizationContext _context = null;        public Form1()        {            InitializeComponent();            IPAddress[] IP = Dns.GetHostAddresses(Dns.GetHostName());            ServerIP.Text = IP[1].ToString();        }        private void BtnStartListener_Click(object sender, EventArgs e)        {                        foreach (Control c in groupBox1.Controls)             {                 if ((c is RadioButton) && (c as RadioButton).Checked)                 {                     Tcplx = c.Text;                }             }            if (Tcplx == "服务端")            {                BtnStartListener.Enabled = false;                BtnStopListener.Enabled = true;                //第1步:建立套接字,返回套接字                newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);                //第2步:将套接字与网络端点相连                IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ServerIP.Text), int.Parse(ServerPort.Text)); //网络端点(IP 地址和端口号)                newsock.Bind(ipep);//套接字绑定网络端点                //第3步:并通知TCP,服务器准备接收                newsock.Listen(10);//设置监听最大连接10,                //连接线程接收连接                Thread connectThread = new Thread(new ThreadStart(AcceptConnect));                connectThread.Start();                //如果当前线程,不在线程列表中,则加入                if (!ThreadList.ContainsKey(connectThread.ManagedThreadId))                {                    ThreadList.Add(connectThread.ManagedThreadId, connectThread);                }                             //_context = SynchronizationContext.Current;            }            if (Tcplx == "客户端")            {                BtnStartListener.Enabled = false;                BtnStopListener.Enabled = true;                newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);                IPEndPoint ie = new IPEndPoint(IPAddress.Parse(ServerIP.Text), int.Parse(ServerPort.Text));//第1步:客户端套接字                try                {                    //因为客户端只是用来向特定的服务器发送信息,所以不需要绑定本机的IP和端口。不需要监听。                    newsock.Connect(ie);                }                catch (SocketException se)                {                    Console.WriteLine("unable to connect to server");                    Console.WriteLine(se.ToString());                    return;                }                Thread receiveThread = new Thread(new ParameterizedThreadStart(ReceiveMessage));//接收线程处理接收的消息                // 启动消息服务线程                receiveThread.Start(newsock);                //如果当前线程,不在线程列表中,则加入                if (!ThreadList.ContainsKey(receiveThread.ManagedThreadId))                {                    ThreadList.Add(receiveThread.ManagedThreadId, receiveThread);                }            }        }        /// <summary>        /// 接收客户端连接        /// </summary>        private void AcceptConnect()        {            while (true)            {                try                {                    Console.WriteLine("客户端连接线程:" + Thread.CurrentThread.ManagedThreadId);                    //第4步:接收连接,等待客户连接                    //第5步:当有可用的客户端连接尝试时执行,并返回一个新的socket                     Socket client = newsock.Accept();//注:每次连接都创建一个客户连接,所以client定义局部的,而不是全局的。Socket是引用类型。                                                          //创建消息服务线程对象,并把连接socket赋于ClientThread                     //ClientThread newclient = new ClientThread(client);                    //方法一:当有N个连接客户端的时候,就有N个线程,会对程序性能以及计算机性能影响很大。                    //把ClientThread 类的ClientService方法委托给线程                    Thread receiveThread = new Thread(new ParameterizedThreadStart(ReceiveMessage));//接收线程处理接收的消息                    // 启动消息服务线程                    receiveThread.Start(client);                    //如果当前线程,不在线程列表中,则加入                    if (!ThreadList.ContainsKey(receiveThread.ManagedThreadId))                    {                        ThreadList.Add(receiveThread.ManagedThreadId, receiveThread);                    }                    //方法二:用线程池的方法对线程进行线程管理(限制最大的线程数,把空闲的线程重新使用,以提高性能)                    //threadpool的静态方法QueueUserWorkItem(这个方法默认最多能有25个线程)                    //ThreadPool.QueueUserWorkItem(new WaitCallback(ClientServer));                }                catch (Exception ex)                {                    Console.Write("出现异常1:");                    Console.WriteLine(ex.ToString());                    Console.ReadLine();                }                            }        }        //数据处理接口        public void ReceiveMessage(object ClientSocket)        {            Socket s = (Socket)ClientSocket;            try            {                while (true)                {                    Console.WriteLine("读数据线程:" + Thread.CurrentThread.ManagedThreadId);                    //第6步:Receive()读数据                    recCount = s.Receive(receiveBytes, receiveBytes.Length, 0);//接收信息放到receiveBytes缓冲区                    if (recCount != 0)//接收字节数不为空                    {                        data = encoding.GetString(receiveBytes, 0, recCount); //字节解码为字符串                        this.Invoke((EventHandler)(delegate                        {                            TextRead.Text += data;                        }));                        //_context.Post((o) =>                        //{                        //    TextRead.Text += data;                        //}, null);                              //第7步:可读取的字节数为0,Send() 写数据,接收数据成功后给客户端返回OK                         if (s.Available==0)                        {                            if (Tcplx == "服务端")                            {                                s.Send(encoding.GetBytes("OK"), 2, 0);                            }                        }                    }                    else {                        break; //客户端断开连接,退出读数据循环                    }                }            }            catch (Exception ex)            {                Console.Write("出现异常2:");                Console.WriteLine(ex.ToString());                Console.ReadLine();            }            s.Close();//第8步:关闭套接字        }        /// <summary>        /// 停止监听        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void BtnStopListener_Click(object sender, EventArgs e)        {            Dictionary<int, Thread>.ValueCollection valueCol = ThreadList.Values;            //关闭全部线程            foreach (Thread t in valueCol)            {                //Thread.Abort()方法来永久销毁一个线程,而且将抛出ThreadAbortException异常。                //并执行s.close 关闭客户连接Socket                t.Abort();            }            ThreadList.Clear();            //关闭服务器Socket            newsock.Close();            //关闭客户连接Socket            //如果是传文件的话还需要关闭流文件close            BtnStartListener.Enabled = true;            BtnStopListener.Enabled = false;        }        /// <summary>        /// 发送信息        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void BtnWrite_Click(object sender, EventArgs e)        {            newsock.Send(encoding.GetBytes(TextWrite.Text));        }        /// <summary>        /// 清除接收数据        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void BtnReadClear_Click(object sender, EventArgs e)        {            TextRead.Text = "";        }        /// <summary>        /// 清空发送数据        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void BtnWriteClear_Click(object sender, EventArgs e)        {            TextWrite.Text = "";        }        private void Form1_FormClosing(object sender, FormClosingEventArgs e)        {               //if (DialogResult.OK == MessageBox.Show("你确定要关闭应用程序吗?", "关闭提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question))                   //{                       //    this.FormClosing -= new FormClosingEventHandler(this.Form1_FormClosing);//为保证Application.Exit();时不再弹出提示,所以将FormClosing事件取消                       //    Application.Exit();//退出整个应用程序                  //}                   //else                   //{                      //    e.Cancel = true;  //取消关闭事件                  //}             Dictionary<int, Thread>.ValueCollection valueCol = ThreadList.Values;            //关闭全部线程            foreach (Thread t in valueCol)            {                //Thread.Abort()方法来永久销毁一个线程,而且将抛出ThreadAbortException异常。                //并执行s.close 关闭客户连接Socket                t.Abort();            }            ThreadList.Clear();            //关闭服务器Socket            newsock.Close();            //关闭客户连接Socket            //如果是传文件的话还需要关闭流文件close            BtnStartListener.Enabled = true;            BtnStopListener.Enabled = false;        }    }}

参考地址:http://www.cnblogs.com/stg609/archive/2008/11/15/1333889.html

0 0