C# 網路編程之使用Socket類Send、Receive方法的同步通訊

來源:互聯網
上載者:User

經過幾天學習,終於解決了再C#網路編程中使用Socket類Send和Receive方法開發的用戶端和服務端的同步通訊程式;實現了又用戶端想伺服器發送訊息的介面程式.主要使用的方法是:

1.Socket通訊端編程的知識,通過IPAddress定義一個IP地址,IPEndPoint定義一個主機,Socket執行個體通訊端對象sock和線程Thread的的成員變數;

2.再調用方法bind綁定連接埠、listen監聽連接埠、accept接受串連請求、connect請求串連來串連用戶端和伺服器;

3.建立串連後通過Send和Receive方法通過線程迴圈接受串連請求中發送的訊息,實現通訊並顯示在相應的控制項中;

4.最後調用socket的close和shutdown方法關閉通訊端,停止串連監聽.

下面是程式運行後的結果:

(服務端接受用戶端發送的訊息:這是一個單方的通訊,但實現雙方的方法相同,因為服務端的"歡飲使用本伺服器"也反饋顯示在了用戶端)

(用戶端)

下面是本程式的原始碼:

服務端

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;//添加新的命名空間using System.Net;using System.Net.Sockets;using System.Threading;namespace tbServer{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        //添加私人成員        private IPAddress myIP = IPAddress.Parse("127.0.0.1");   //定義IP對象        private IPEndPoint MyServer;                             //定義主機        private Socket sock;                                     //通訊端對象執行個體        private bool sign = true;                                //控制迴圈        private Thread thread;                                   //建立控制線程        private Socket socklin;                                  //臨時通訊端,接受用戶端串連請求        //雙擊"開始監聽"按鈕添加Click事件        private void button1_Click(object sender, EventArgs e)        {            try             {                myIP = IPAddress.Parse(textBox1.Text);           //字串轉換為IP            }            catch             {                MessageBox.Show("你輸入的IP地址格式錯誤!");            }            try             {                //定義主機                MyServer = new IPEndPoint(myIP, Int32.Parse(textBox2.Text));                //構造通訊端                sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);                //綁定連接埠                sock.Bind(MyServer);                //開始監聽                sock.Listen(10);                //狀態列資訊添加 textBox3替代statusStrip1(不會用)                textBox3.Text = "主機" + textBox1.Text + " 連接埠" + textBox2.Text + " 開始監聽";                //構造線程                thread = new Thread(new ThreadStart(targett)); //targett自訂函數:接受用戶端串連請求                //啟動線程用於接受串連和接受資料                thread.Start();            }            catch(Exception msg) {                textBox3.Text = msg.Message;            }        }        //targett():自訂函數,該方法迴圈開始接受用戶端的串連請求        private void targett()        {            socklin = sock.Accept();   //接受串連請求            sign = true;               //迴圈標誌變數true            //串連            if (socklin.Connected)            {                textBox3.Text = "與用戶端串連";                //資訊反饋給用戶端Client                 Byte[] byteNum = new Byte[64];                     //構造位元組數組                byteNum = System.Text.Encoding.BigEndianUnicode.GetBytes("歡飲使用本伺服器".ToCharArray());                socklin.Send(byteNum,byteNum.Length,0);            //發送資料                //sign為true 迴圈接受資料                while (sign)                {                    Byte[] byteNum2 = new Byte[128];                    socklin.Receive(byteNum2,byteNum2.Length,0);   //接受資料                    string str = System.Text.Encoding.BigEndianUnicode.GetString(byteNum2);                    richTextBox1.AppendText(str+"\r\n");           //顯示字串                                       //擷取richTextBox1行數                    int length = richTextBox1.Lines.Length;                            //如果用戶端發送倒數第二行的字串為"@@@" 中斷連線                    if(richTextBox1.Lines[length-2]=="@@@")                    {                        textBox3.Text = "與用戶端中斷連線";                        //關閉通訊端執行個體(both表示發送和接受關閉)                        socklin.Shutdown(System.Net.Sockets.SocketShutdown.Both);                         socklin.Close();                        sign = false;                //設為false退出迴圈                    }                }            }        }        //雙擊"停止監聽"按鈕添加Click事件        private void button2_Click(object sender, EventArgs e)        {            try             {                sign = false;                sock.Close();                textBox3.Text = "主機" + textBox1.Text + "連接埠" + textBox2.Text + "監聽停止";            }            catch             {                MessageBox.Show("監聽尚未開始,關閉無效!");            }        }        //載入Form是設定非安全訪問,防止線程無效操作        private void Form1_Load(object sender, EventArgs e)        {            //非安全線程訪問,不檢查線程是否安全            Control.CheckForIllegalCrossThreadCalls = false;            }    }}

用戶端

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;//添加新的命名空間using System.Net;using System.Net.Sockets;using System.Threading;namespace tbClient{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        //添加私人成員        private IPAddress myIP = IPAddress.Parse("127.0.0.1");   //定義IP對象        private IPEndPoint MyServer;                             //定義主機        private Socket sock;                                     //通訊端對象執行個體        private Thread thread;                                   //建立控制線程               //雙擊"請求串連"按鈕添加Click事件        private void button1_Click(object sender, EventArgs e)        {            try             {                myIP = IPAddress.Parse(textBox1.Text);           //字串轉換為IP            }            catch             {                MessageBox.Show("你輸入的IP地址格式錯誤!");            }            try             {                //構造主機                MyServer = new IPEndPoint(myIP, Int32.Parse(textBox2.Text));                //構造通訊端                sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);                //請求串連                sock.Connect(MyServer);                //構造線程                thread = new Thread(new ThreadStart(targett)); //targett自訂函數:接受用戶端串連請求                //啟動線程用於接受串連和接受資料                thread.Start();                //輸出資訊                textBox4.Text = "與主機" + textBox1.Text + " 連接埠" + textBox2.Text + " 串連成功";            }            catch(Exception msg)             {                MessageBox.Show(msg.Message);            }        }        //targett():自訂函數,該方法迴圈開始接受用戶端的串連請求        private void targett()        {            //構造位元組數組            Byte[] byteNum = new Byte[64];              //接受資料                   sock.Receive(byteNum, byteNum.Length, 0);                      //將字元數群組轉換為字串            string str = System.Text.Encoding.BigEndianUnicode.GetString(byteNum);            textBox3.Text = str;        }        //雙擊"發送訊息"按鈕添加Click事件        private void button2_Click(object sender, EventArgs e)        {            //構造位元組數組            Byte[] byteNum = new Byte[64];              //發送內容            string send = richTextBox1.Text + "\r\n";            //將字串轉換為位元組數組            byteNum = System.Text.Encoding.BigEndianUnicode.GetBytes(send.ToCharArray());            //發送資料            sock.Send(byteNum,byteNum.Length,0);            //構造線程            Thread threadSend = new Thread(new ThreadStart(targett));            //啟動線程接受資料            threadSend.Start();        }        //雙擊"關閉串連"按鈕添加Click事件        private void button3_Click(object sender, EventArgs e)        {            Byte[] byteNum = new Byte[64];            string send = "@@@" + "\r\n";            byteNum = System.Text.Encoding.BigEndianUnicode.GetBytes(send.ToCharArray());            sock.Send(byteNum, byteNum.Length, 0);   //將"@@@"發送給伺服器            try             {                sock.Close();                textBox4.Text="主機" + textBox1.Text + "連接埠" + textBox2.Text + "中斷連線";            }            catch             {                MessageBox.Show("串連尚未建立,斷開無效!");            }        }        //載入Form是設定非安全訪問,防止線程無效操作        private void Form1_Load(object sender, EventArgs e)        {            //非安全線程訪問,不檢查線程是否安全            Control.CheckForIllegalCrossThreadCalls = false;           }    }}

該程式中我遇到的幾個主要問題及解決方案如下:

 1.程式初期總是很卡,出現多次未響應情況?

因為socket的Accept()函數是阻塞模式,它的執行會造成程式的阻塞,應該把它放置到線程中執行,否則會阻塞當前線程,出現卡死狀態不響應訊息,後續代碼也不會執行,所以需要把accept放到建立的線程thread中,放入targett()函數中的“socklin = sock.accept()”即可實現;

2.在定義的socket對象執行個體中sock與socklin(臨時接受用戶端串連請求)中混淆?

socklin = sock.accept,它就是用戶端發送串連的請求,因此在判斷串連時是if(socklin.Connected),同時使用socklin的send和receive方法發送和接受資料;

3.總是出現“線程間操作無效:從不是建立控制項的線程訪問它”的錯誤?

因為windows表單控制項不是安全執行緒的,如果幾個線程操作某一控制項的狀態,可能會使該控制項的狀態不一致,出現爭用或死結狀態.我採用的解決方案是添加Form的載入load事件,在load時將CheckForIllegalCrossThreadCalls 屬性的值設定為 false .這樣進行非安全線程訪問時,運行環境就不去檢驗它是否是安全執行緒的.這是來自與該部落格,詳細情況見:http://blog.csdn.net/wangchao0605/article/details/5010864

總結:

最後經過一星期的學習與查閱資料,還是把這個程式弄出來了,也學到了很多東西,同時感謝上面的博主和一些書籍.希望這篇文章對大家有用,有錯或不足之處見諒!

(BY:Eastmount 2013-7-22)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.