看到這個題目,是不是很眼熟?在博客園裏搜下,保證會發現關於這個東東的文章實在是太多了~~~真得是沒有寫得必要,而且我也有點懶得去琢磨字
句。(看到這,肯定得來個轉折的了,不然就看不到下文了,不是嗎)但是,爲了自己下一篇要寫的文章做參考,還是有必要先補充一下socket基礎知識。
注意:如果你已經接觸過socket,那就沒什麼必要耽誤時間看下去了。另外,如果發現其中任何錯誤,歡迎直接指出。
1.按慣例先來介紹下socket
Windows
中的很多東西都是從Unix領域借鑑過來的,Socket也是一樣。在Unix中,socket代表了一種文件描述符(在Unix中一切都是以文件爲單
位),而這裏這個描述符則是用於描述網絡訪問的。什麼意思呢?就是程序員可以通過socket來發送和接收網絡上的數據。你也可以理解成是一個API。有
了它,你就不用直接去操作網卡了,而是通過這個接口,這樣就省了很多複雜的操作。
在C#中,MS爲我們提供了 System.Net.Sockets 命名空間,裏面包含了Socket類。
2.有了socket,那就可以用它來訪問網絡了
不過你不要高興得太早,要想訪問網絡,還得有些基本的條件(和編程無關的我就不提了):a.
要確定本機的IP和端口,socket只有與某一IP和端口綁定,才能發揮強大的威力。b.
得有協議吧(否則誰認得你這發送到網絡的是什麼呀)。想要複雜的,我們可以自己來定協議。但是這個就不在這篇裏提了,我這裏介紹兩種大家最熟悉不過的協
議:TCP & UDP。(別說你不知道,不然...不然...我不告訴你)
如果具備了基本的條件,就可以開始用它們訪問網絡了。來看看步驟吧:
a. 建立一個套接字
b. 綁定本機的IP和端口
c. 如果是TCP,因爲是面向連接的,所以要利用ListenO()方法來監聽網絡上是否有人給自己發東西;如果是UDP,因爲是無連接的,所以來者不拒。
d.
TCP情況下,如果監聽到一個連接,就可以使用accept來接收這個連接,然後就可以利用Send/Receive來執行操作了。而UDP,則不需要
accept,
直接使用SendTo/ReceiveFrom來執行操作。(看清楚哦,和TCP的執行方法有區別,因爲UDP不需要建立連接,所以在發送前並不知道對方
的IP和端口,因此需要指定一個發送的節點才能進行正常的發送和接收)
e. 如果你不想繼續發送和接收了,就不要浪費資源了。能close的就close吧。
如果看了上面文字,你還不清楚的話,就來看看圖好了:
面向連接的套接字系統調用時序
無連接的套接字系統調用時序
3.開始動手敲~~代碼(簡單的代碼)
首先我們來寫個面向連接的
TCPServer
using
System;
using
System.Net;
using
System.Net.Sockets;
using
System.Text;
namespace
tcpserver
{
///
<summary>
///
Class1 的摘要說明。
///
</summary>
class
server
{
///
<summary>
///
應用程序的主入口點。
///
</summary>
[STAThread]
static
void
Main(
string
[] args)
{
//
//
TODO: 在此處添加代碼以啓動應用程序
//
int
recv;
//
用於表示客戶端發送的信息長度
byte
[] data
=
new
byte
[
1024
];
//
用於緩存客戶端所發送的信息,通過socket傳遞的信息必須爲字節數組
IPEndPoint ipep
=
new
IPEndPoint(IPAddress.Any,
9050
);
//
本機預使用的IP和端口
Socket newsock
=
new
Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
newsock.Bind(ipep);
//
綁定
newsock.Listen(
10
);
//
監聽
Console.WriteLine(
"
waiting for a client
"
);
Socket client
=
newsock.Accept();
//
當有可用的客戶端連接嘗試時執行,並返回一個新的socket,用於與客戶端之間的通信
IPEndPoint clientip
=
(IPEndPoint)client.RemoteEndPoint;
Console.WriteLine(
"
connect with client:
"
+
clientip.Address
+
"
at port:
"
+
clientip.Port);
string
welcome
=
"
welcome here!
"
;
data
=
Encoding.ASCII.GetBytes(welcome);
client.Send(data,data.Length,SocketFlags.None);
//
發送信息
while
(
true
)
{
//
用死循環來不斷的從客戶端獲取信息
data
=
new
byte
[
1024
];
recv
=
client.Receive(data);
Console.WriteLine(
"
recv=
"
+
recv);
if
(recv
==
0
)
//
當信息長度爲0,說明客戶端連接斷開
break
;
Console.WriteLine(Encoding.ASCII.GetString(data,
0
,recv));
client.Send(data,recv,SocketFlags.None);
}
Console.WriteLine(
"
Disconnected from
"
+
clientip.Address);
client.Close();
newsock.Close();
}
}
}
TCPClient
using
System;
using
System.Net;
using
System.Net.Sockets;
using
System.Text;
namespace
tcpclient
{
///
<summary>
///
Class1 的摘要說明。
///
</summary>
class
client
{
///
<summary>
///
應用程序的主入口點。
///
</summary>
[STAThread]
static
void
Main(
string
[] args)
{
//
//
TODO: 在此處添加代碼以啓動應用程序
//
byte
[] data
=
new
byte
[
1024
];
Socket newclient
=
new
Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
Console.Write(
"
please input the server ip:
"
);
string
ipadd
=
Console.ReadLine();
Console.WriteLine();
Console.Write(
"
please input the server port:
"
);
int
port
=
Convert.ToInt32(Console.ReadLine());
IPEndPoint ie
=
new
IPEndPoint(IPAddress.Parse(ipadd),port);
//
服務器的IP和端口
try
{
//
因爲客戶端只是用來向特定的服務器發送信息,所以不需要綁定本機的IP和端口。不需要監聽。
newclient.Connect(ie);
}
catch
(SocketException e)
{
Console.WriteLine(
"
unable to connect to server
"
);
Console.WriteLine(e.ToString());
return
;
}
int
recv
=
newclient.Receive(data);
string
stringdata
=
Encoding.ASCII.GetString(data,
0
,recv);
Console.WriteLine(stringdata);
while
(
true
)
{
string
input
=
Console.ReadLine();
if
(input
==
"
exit
"
)
break
;
newclient.Send(Encoding.ASCII.GetBytes(input));
data
=
new
byte
[
1024
];
recv
=
newclient.Receive(data);
stringdata
=
Encoding.ASCII.GetString(data,
0
,recv);
Console.WriteLine(stringdata);
}
Console.WriteLine(
"
disconnect from sercer
"
);
newclient.Shutdown(SocketShutdown.Both);
newclient.Close();
}
}
}
下面在給出無連接的(實在是太懶了,下面這個是直接複製別人的)
UDPServer
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Net;
using
System.Net.Sockets;
namespace
SimpleUdpSrvr
{
class
Program
{
static
void
Main(
string
[] args)
{
int
recv;
byte
[] data
=
new
byte
[
1024
];
IPEndPoint ipep
=
new
IPEndPoint(IPAddress.Any,
9050
);
//
定義一網絡端點
Socket newsock
=
new
Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//
定義一個Socket
newsock.Bind(ipep);
//
Socket與本地的一個終結點相關聯
Console.WriteLine(
"
Waiting for a client
..
"
);
IPEndPoint sender
=
new
IPEndPoint(IPAddress.Any,
0
);
//
定義要發送的計算機的地址
EndPoint Remote
=
(EndPoint)(sender);
//
recv
=
newsock.ReceiveFrom(data,
ref
Remote);
//
接受數據
Console.WriteLine(
"
Message received from{0}:
"
, Remote.ToString());
Console.WriteLine(Encoding.ASCII.GetBytes(data,
0
,recv));
string
welcome
=
"
Welcome to my test server!
"
;
data
=
Encoding.ASCII.GetBytes(welcome);
newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
while
(
true
)
{
data
=
new
byte
[
1024
];
recv
=
newsock.ReceiveFrom(data,
ref
Remote);
Console.WriteLine(Encoding.ASCII.GetString(data,
0
, recv));
newsock.SendTo(data, recv, SocketFlags.None, Remote);
}
}
}
}
UDPClient
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Net;
using
System.Net.Sockets;
namespace
SimpleUdpClient
{
class
Program
{
static
void
Main(
string
[] args)
{
byte
[] data
=
new
byte
[
1024
];
//
定義一個數組用來做數據的緩衝區
string
input, stringData;
IPEndPoint ipep
=
new
IPEndPoint(IPAddress.Parse(
"
127.0.0.1
"
),
9050
);
Socket server
=
new
Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
string
welcome
=
"
Hello,are you there?
"
;
data
=
Encoding.ASCII.GetBytes(welcome);
server.SendTo(data, data.Length, SocketFlags.None, ipep);
//
將數據發送到指定的終結點
IPEndPoint sender
=
new
IPEndPoint(IPAddress.Any,
0
);
EndPoint Remote
=
(EndPoint)sender;
data
=
new
byte
[
1024
];
int
recv
=
server.ReceiveFrom(data,
ref
Remote);
//
接受來自服務器的數據
Console.WriteLine(
"
Message received from{0}:
"
, Remote.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data,
0
, recv));
while
(
true
)
//
讀取數據
{
input
=
Console.ReadLine();
//
從鍵盤讀取數據
if
(input
==
"
text
"
)
//
結束標記
{
break
;
}
server.SendTo(Encoding.ASCII.GetBytes(input), Remote);
//
將數據發送到指定的終結點Remote
data
=
new
byte
[
1024
];
recv
=
server.ReceiveFrom(data,
ref
Remote);
//
從Remote接受數據
stringData
=
Encoding.ASCII.GetString(data,
0
, recv);
Console.WriteLine(stringData);
}
Console.WriteLine(
"
Stopping client
"
);
server.Close();
}
}
}
上面的示例只是簡單的應用了socket來實現通信,你也可以實現異步socket、IP組播 等等。
MS還爲我們提供了幾個助手類:TcpClient類、TcpListener類、UDPClient類。這幾個類簡化了一些操作,所以你也可以利用這幾類來寫上面的代碼,但我個人還是比較習慣直接用socket來寫。
既然快寫完了,那我就再多囉嗦幾句。在需要即時響應的軟件中,我個人更傾向使用UDP來實現通信,因爲相比TCP來說,UDP佔用更少的資源,且響應速度
快,延時低。至於UDP的可靠性,則可以通過在應用層加以控制來滿足。當然如果可靠性要求高的環境下,還是建議使用TCP。
--------------------------------------------------------------------------------------------------------------
URL: http://www.cnblogs.com/stg609/archive/2008/11/15/1333889.html