C#之Socket的簡單使用

Socket是一種通訊TCP/IP的通信接口,也就是HTTP的抽象層,就是Socket在Http之上,Socket也就是發動機。實際上,傳輸層的TCP是基於網絡層的IP協議的,而應用層的HTTP協議又是基於傳輸層的TCP協議的,而Socket自己不算是協議,就像上面所說,它只是提供了一個針對TCP或者UDP編程的接口。在C#中能夠很是方便的使用Socket進行數據傳輸。編程

Socket對象是C#使用它的重要對象在Socket的構造函數中,咱們能夠設置它的地址,Socket的類,支持的協議等等,其定義以下:數組

public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);

咱們想要使用Socket,那麼就必須建立Socket的對象,建立這個對象,就必須須要IPEndPoint對象來綁定到套接詞字中,有以下定義緩存

// 建立負責監聽的套接字,注意其中的參數;  
socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 得到文本框中的IP對象;
IPAddress address = IPAddress.Parse(textBox1.Text.Trim());
// 建立包含ip和端口號的網絡節點對象;  
IPEndPoint endPoint = new IPEndPoint(address, int.Parse(textBox2.Text.Trim()));

 而後再經過Socket的Bind來進行綁定。服務器

socketWatch.Bind(endPoint);

由於咱們時刻會被內網中的其餘ip和端口進行鏈接,那麼咱們就須要建立線程來進行觀察,有以下定義網絡

// 設置監聽隊列的長度;  
            socketWatch.Listen(10);
            // 建立負責監聽的線程;  
            threadWatch = new Thread(WatchConnecting);
            threadWatch.IsBackground = true;
            threadWatch.Start();
            ShowMsg("服務器啓動監聽成功!");

其檢測方法以下,其中就是不斷的去檢測客戶端的鏈接請求,經過Accept()方法能夠獲取一個套接字,而後經過Socket對象的RemoteEndPoint()能夠獲取一個IP。socket

void WatchConnecting()
        {
            while (true)  // 持續不斷的監聽客戶端的鏈接請求;  
            {
                // 開始監聽客戶端鏈接請求,Accept方法會阻斷當前的線程;  
                Socket sokConnection = socketWatch.Accept(); // 一旦監聽到一個客戶端的請求,就返回一個與該客戶端通訊的 套接字;  
                // 想列表控件中添加客戶端的IP信息;  
                Online.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);  //  將新建的線程 添加 到線程的集合中去。  
            }
        }

最後咱們開啓一個線程去執行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  
                    Online.Items.Remove(sokClient.RemoteEndPoint.ToString());
                    break;
                }
                catch (Exception e)
                {
                    ShowMsg("異常:" + e.Message);
                    // 從 通訊套接字 集合中刪除被中斷鏈接的通訊套接字;  
                    dict.Remove(sokClient.RemoteEndPoint.ToString());
                    // 從通訊線程集合中刪除被中斷鏈接的通訊線程對象;  
                    dictThread.Remove(sokClient.RemoteEndPoint.ToString());
                    // 從列表中移除被中斷的鏈接IP  
                    Online.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);
                        }
                    }
                }
            }
        }

咱們在方法中得到了一個Object類型的對象,將這個Object對象轉換成了Socket,而後咱們經過Socket的方法Receive()方法接收返回的數據,其中裏面有它的屬性,能夠獲取ip還有一些數據等等。服務器向客戶端發送數據也是很是簡單。經過Send方法就能夠了,如如下定義:this

string strMsg = "服務器" + "\r\n" + "   -->" + richTextBox1.Text.Trim() + "\r\n";
            byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg); // 將要發送的字符串轉換成Utf-8字節數組;  
            byte[] arrSendMsg = new byte[arrMsg.Length + 1];
            arrSendMsg[0] = 0; // 表示發送的是消息數據  
            Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length);
            string strKey = "";
            strKey = Online.Text.Trim();
            if (string.IsNullOrEmpty(strKey))   // 判斷是否是選擇了發送的對象;  
            {
                MessageBox.Show("請選擇你要發送的好友!!!");
            }
            else
            {
                dict[strKey].Send(arrSendMsg);// 解決了 sokConnection是局部變量,不能再本函數中引用的問題;  
                ShowMsg(strMsg);
                richTextBox1.Clear();
            }

 最後須要注意的是,若是你的文件較大,有的時候這個緩衝區達不到你的文件字節那麼大,那麼就會截斷,因此與的時候,先將文件轉換爲Byte是正確的作法。只要在客戶端進行逆轉就能夠了!spa

相關文章
相關標籤/搜索