以下範例程式實現簡單的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
. 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.ChangeRickBox), new
object[ , 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())
;
做
點
當客戶端連線時,在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.T5)
;建立與遠端主機的連接
//啟動新執行緒用來接收資料
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);
(this.rtbReceive.InvokeRequired)
{
this.rtbReceive.Invoke(new EventHandler(ChangeRtb), new object[]
{ strRec, EventArgs.Empty });
}
}
}
catch(Exception ex)
{
MessageBox.Showor"Recealive. "+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
}(byatchSend);
}
{
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("Exitrror") ;
}
}
}
}
不解之處:
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.cnblogs.com/KissKnife/archive/2006/08/13/475707.html