C# 网络编程之使用Socket类Send、Receive方法的同步通讯
? ? ? 經(jīng)過幾天學(xué)習(xí),終于解決了再C#網(wǎng)絡(luò)編程中使用Socket類Send和Receive方法開發(fā)的客戶端和服務(wù)端的同步通訊程序;實(shí)現(xiàn)了又客戶端想服務(wù)器發(fā)送消息的界面程序.主要使用的方法是:
? ? ? 1.Socket套接字編程的知識(shí),通過IPAddress定義一個(gè)IP地址,IPEndPoint定義一個(gè)主機(jī),Socket實(shí)例套接字對(duì)象sock和線程Thread的的成員變量;
? ? ? 2.再調(diào)用方法bind綁定端口、listen監(jiān)聽端口、accept接受連接請(qǐng)求、connect請(qǐng)求連接來(lái)連接客戶端和服務(wù)器;
? ? ? 3.建立連接后通過Send和Receive方法通過線程循環(huán)接受連接請(qǐng)求中發(fā)送的消息,實(shí)現(xiàn)通信并顯示在相應(yīng)的控件中;
? ? ? 4.最后調(diào)用socket的close和shutdown方法關(guān)閉套接字,停止連接監(jiān)聽.
? ? ? 下面是程序運(yùn)行后的結(jié)果:
? ? ? (服務(wù)端接受客戶端發(fā)送的消息:這是一個(gè)單方的通信,但實(shí)現(xiàn)雙方的方法相同,因?yàn)榉?wù)端的"歡飲使用本服務(wù)器"也反饋顯示在了客戶端)
? ? ? (客戶端)
? ? ? 下面是本程序的源代碼:
? ? ? 服務(wù)端
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對(duì)象private IPEndPoint MyServer; //定義主機(jī)private Socket sock; //套接字對(duì)象實(shí)例private bool sign = true; //控制循環(huán)private Thread thread; //創(chuàng)建控制線程private Socket socklin; //臨時(shí)套接字,接受客戶端連接請(qǐng)求//雙擊"開始監(jiān)聽"按鈕添加Click事件private void button1_Click(object sender, EventArgs e){try {myIP = IPAddress.Parse(textBox1.Text); //字符串轉(zhuǎn)換為IP}catch {MessageBox.Show("你輸入的IP地址格式錯(cuò)誤!");}try {//定義主機(jī)MyServer = new IPEndPoint(myIP, Int32.Parse(textBox2.Text));//構(gòu)造套接字sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//綁定端口sock.Bind(MyServer);//開始監(jiān)聽sock.Listen(10);//狀態(tài)欄信息添加 textBox3替代statusStrip1(不會(huì)用)textBox3.Text = "主機(jī)" + textBox1.Text + " 端口" + textBox2.Text + " 開始監(jiān)聽";//構(gòu)造線程thread = new Thread(new ThreadStart(targett)); //targett自定義函數(shù):接受客戶端連接請(qǐng)求//啟動(dòng)線程用于接受連接和接受數(shù)據(jù)thread.Start();}catch(Exception msg) {textBox3.Text = msg.Message;}}//targett():自定義函數(shù),該方法循環(huán)開始接受客戶端的連接請(qǐng)求private void targett(){socklin = sock.Accept(); //接受連接請(qǐng)求sign = true; //循環(huán)標(biāo)志變量true//連接if (socklin.Connected){textBox3.Text = "與客戶端連接";//信息反饋給客戶端Client Byte[] byteNum = new Byte[64]; //構(gòu)造字節(jié)數(shù)組byteNum = System.Text.Encoding.BigEndianUnicode.GetBytes("歡飲使用本服務(wù)器".ToCharArray());socklin.Send(byteNum,byteNum.Length,0); //發(fā)送數(shù)據(jù)//sign為true 循環(huán)接受數(shù)據(jù)while (sign){Byte[] byteNum2 = new Byte[128];socklin.Receive(byteNum2,byteNum2.Length,0); //接受數(shù)據(jù)string str = System.Text.Encoding.BigEndianUnicode.GetString(byteNum2);richTextBox1.AppendText(str+"\r\n"); //顯示字符串//獲取richTextBox1行數(shù)int length = richTextBox1.Lines.Length; //如果客戶端發(fā)送倒數(shù)第二行的字符串為"@@@" 斷開連接if(richTextBox1.Lines[length-2]=="@@@"){textBox3.Text = "與客戶端斷開連接";//關(guān)閉套接字實(shí)例(both表示發(fā)送和接受關(guān)閉)socklin.Shutdown(System.Net.Sockets.SocketShutdown.Both); socklin.Close();sign = false; //設(shè)為false退出循環(huán)}}}}//雙擊"停止監(jiān)聽"按鈕添加Click事件private void button2_Click(object sender, EventArgs e){try {sign = false;sock.Close();textBox3.Text = "主機(jī)" + textBox1.Text + "端口" + textBox2.Text + "監(jiān)聽停止";}catch {MessageBox.Show("監(jiān)聽尚未開始,關(guān)閉無(wú)效!");}}//載入Form是設(shè)置非安全訪問,防止線程無(wú)效操作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對(duì)象private IPEndPoint MyServer; //定義主機(jī)private Socket sock; //套接字對(duì)象實(shí)例private Thread thread; //創(chuàng)建控制線程//雙擊"請(qǐng)求連接"按鈕添加Click事件private void button1_Click(object sender, EventArgs e){try {myIP = IPAddress.Parse(textBox1.Text); //字符串轉(zhuǎn)換為IP}catch {MessageBox.Show("你輸入的IP地址格式錯(cuò)誤!");}try {//構(gòu)造主機(jī)MyServer = new IPEndPoint(myIP, Int32.Parse(textBox2.Text));//構(gòu)造套接字sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//請(qǐng)求連接sock.Connect(MyServer);//構(gòu)造線程thread = new Thread(new ThreadStart(targett)); //targett自定義函數(shù):接受客戶端連接請(qǐng)求//啟動(dòng)線程用于接受連接和接受數(shù)據(jù)thread.Start();//輸出信息textBox4.Text = "與主機(jī)" + textBox1.Text + " 端口" + textBox2.Text + " 連接成功";}catch(Exception msg) {MessageBox.Show(msg.Message);}}//targett():自定義函數(shù),該方法循環(huán)開始接受客戶端的連接請(qǐng)求private void targett(){//構(gòu)造字節(jié)數(shù)組Byte[] byteNum = new Byte[64]; //接受數(shù)據(jù) sock.Receive(byteNum, byteNum.Length, 0); //將字符數(shù)組轉(zhuǎn)換為字符串string str = System.Text.Encoding.BigEndianUnicode.GetString(byteNum);textBox3.Text = str;}//雙擊"發(fā)送消息"按鈕添加Click事件private void button2_Click(object sender, EventArgs e){//構(gòu)造字節(jié)數(shù)組Byte[] byteNum = new Byte[64]; //發(fā)送內(nèi)容string send = richTextBox1.Text + "\r\n";//將字符串轉(zhuǎn)換為字節(jié)數(shù)組byteNum = System.Text.Encoding.BigEndianUnicode.GetBytes(send.ToCharArray());//發(fā)送數(shù)據(jù)sock.Send(byteNum,byteNum.Length,0);//構(gòu)造線程Thread threadSend = new Thread(new ThreadStart(targett));//啟動(dòng)線程接受數(shù)據(jù)threadSend.Start();}//雙擊"關(guān)閉連接"按鈕添加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); //將"@@@"發(fā)送給服務(wù)器try {sock.Close();textBox4.Text="主機(jī)" + textBox1.Text + "端口" + textBox2.Text + "斷開連接";}catch {MessageBox.Show("連接尚未建立,斷開無(wú)效!");}}//載入Form是設(shè)置非安全訪問,防止線程無(wú)效操作private void Form1_Load(object sender, EventArgs e){//非安全線程訪問,不檢查線程是否安全Control.CheckForIllegalCrossThreadCalls = false; }} }? ? ? 該程序中我遇到的幾個(gè)主要問題及解決方法如下:
? ? ? 1.程序初期總是很卡,出現(xiàn)多次未響應(yīng)情況?
? ? ? 因?yàn)閟ocket的Accept()函數(shù)是阻塞模式,它的執(zhí)行會(huì)造成程序的阻塞,應(yīng)該把它放置到線程中執(zhí)行,否則會(huì)阻塞當(dāng)前線程,出現(xiàn)卡死狀態(tài)不響應(yīng)消息,后續(xù)代碼也不會(huì)執(zhí)行,所以需要把a(bǔ)ccept放到創(chuàng)建的線程thread中,放入targett()函數(shù)中的“socklin = sock.accept()”即可實(shí)現(xiàn);
? ? ? 2.在定義的socket對(duì)象實(shí)例中sock與socklin(臨時(shí)接受客戶端連接請(qǐng)求)中混淆?
? ? ? socklin = sock.accept,它就是客戶端發(fā)送連接的請(qǐng)求,因此在判斷連接時(shí)是if(socklin.Connected),同時(shí)使用socklin的send和receive方法發(fā)送和接受數(shù)據(jù);
? ? ? 3.總是出現(xiàn)“線程間操作無(wú)效:從不是創(chuàng)建控件的線程訪問它”的錯(cuò)誤?
? ? ? 因?yàn)閣indows窗體控件不是線程安全的,如果幾個(gè)線程操作某一控件的狀態(tài),可能會(huì)使該控件的狀態(tài)不一致,出現(xiàn)爭(zhēng)用或死鎖狀態(tài).我采用的解決方法是添加Form的載入load事件,在load時(shí)將CheckForIllegalCrossThreadCalls 屬性的值設(shè)置為 false .這樣進(jìn)行非安全線程訪問時(shí),運(yùn)行環(huán)境就不去檢驗(yàn)它是否是線程安全的.這是來(lái)自與該博客,詳細(xì)情況見:http://blog.csdn.net/wangchao0605/article/details/5010864
? ? ? 總結(jié):
? ? ? 最后經(jīng)過一星期的學(xué)習(xí)與查閱資料,還是把這個(gè)程序弄出來(lái)了,也學(xué)到了很多東西,同時(shí)感謝上面的博主和一些書籍.希望這篇文章對(duì)大家有用,有錯(cuò)或不足之處見諒!
? ? ? (BY:Eastmount 2013-7-22 ?http://blog.csdn.net/eastmount/)
總結(jié)
以上是生活随笔為你收集整理的C# 网络编程之使用Socket类Send、Receive方法的同步通讯的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MFC 基础知识:主对话框与子对话框(二
- 下一篇: C# 网络编程之最简单浏览器实现