以下示例程序實現簡單的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()?
http://www.49028c.com/KissKnife/archive/2006/08/13/475707.html
新聞熱點
疑難解答