一,、摘要
總結一下基于C#的TCP傳輸協(xié)議的涉及到的常用方法及同步實現(xiàn),。
二,、實驗平臺
Visual Studio 2010
三、socket編程的一些常用方法(同步實現(xiàn))
3.1 命名空間
需要添加的命名空間
using System.Net;
using System.Net.Socket;
3.2 構造新的socket對象
socket原型:
public socket (AddressFamily addressFamily,SocketType sockettype,ProtocolType protocolType)
(1) AddressFamily 用來指定socket解析地址的尋址方案,,Inte.Network標示需要ip版本4的地址,,Inte.NetworkV6需要ip版本6的地址;
(2) SocketType 參數(shù)指定socket類型,,Raw支持基礎傳輸協(xié)議訪問,,Stream支持可靠,雙向,,基于連接的數(shù)據(jù)流,;
(3) ProtocolType 表示socket支持的網絡協(xié)議,如常用的TCP和UDP協(xié)議,。
3.3 定義主機對象 (1) IPEndPoint類
原型:
a)
public IPEndPoint(IPAddress address,int port)
參數(shù)address可以直接填寫主機的IP,,如"192.168.2.1";
b)
public IPEndPoint(long address,int port)
參數(shù)address整型int64如123456,,參數(shù)port端口int32,,如6655。
(2) 利用DNS服務器解析主機,,使用Dns.Resolve方法
原型:
public static IPHostEntry Resolve(string hostname)
參數(shù):待解析的主機名稱,,返回IPHostEntry類值,IPHostEntry為Inte.Net主機地址信息提供容器,,該容器提供存有IP地址列表,,主機名稱等。
(3) Dns.GetHostByName獲取本地主機名稱
原型:
public static IPHostEntry GetHostByName(string hostname)
(4) GetHostByAddress
原型:
a)
public static IPHostEntry GetHostByAddress(IPAddress address)
參數(shù):IP地址,。
b)
public static IPHostEntry GetHostByAddress(string address)
參數(shù):IP地址格式化字符串,。
3.4 端口綁定和監(jiān)聽
同步套接字服務器主機的綁定和端口監(jiān)聽,Socket類的Bind(綁定主機),,Listen(監(jiān)聽端口),,Accept(接收客戶端的連接請求)。
(1) Bind
原型:
public void Bind(EndPoint LocalEP)
參數(shù)為主機對象 IPEndPoint
(2) Listen
原型:
public void Listen(int backlog)
參數(shù)整型數(shù)值,,掛起隊列最大值
(3) accept
原型:
返回為套接字對象
3.5 socket的發(fā)送和接收方法
(1) 發(fā)送數(shù)據(jù)
a)socket類的send方法
原型一:
public int Send(byte[] buffer)
參數(shù):待發(fā)送的字節(jié)數(shù)組,;
原型二:
public int Send(byte[],SocketFlags)
SocketFlags成員列表:
DontRoute不使用路由表發(fā)送,
MaxIOVectorLength為發(fā)送和接收數(shù)據(jù)的wsabuf結構數(shù)量提供標準值,,
None 不對次調用使用標志,,
OutOfBand消息的部分發(fā)送或接收,
Partial消息的部分發(fā)送或接收,,
Peek查看傳入的消息,。
原型三:
public int Send(byte[],int,SocketFlags)
參數(shù)二要發(fā)送的字節(jié)數(shù)
原型四:
public int Send(byte[],int,int,SocketFlags)
參數(shù)二為Byte[]中開始發(fā)送的位置
b) NetWordStream類的Write方法
原型:
public override void write(byte[] buffer,int offset,int size)
參數(shù)分別為:字節(jié)數(shù)組,開始字節(jié)位置,總字節(jié)數(shù),。
(2) 接收數(shù)據(jù)
a) Socket類Receive方法
原型一:
public int Receive(byte[] buffer)
原型二:
public int Receive(byte[],SocketFlags)
原型三:
public int Receive(byte[],int,SocketFlags)
原型四:
public int Receive(byte[],int,int,SocketFlags)
Socket類Receive方法的相關參數(shù)可參看Socket類Send方法中的參數(shù),。
b) NetworkStream類的Read方法
public override int Read(int byte[] buffer,int offset,int size)
參數(shù)可參看NetworkStream類的Write方法。
四,、TCP傳輸協(xié)議的同步實現(xiàn)
4.1 服務器端編程的步驟:
(1) 創(chuàng)建套接字,;
(2) 綁定套接字到一個IP地址和一個端口上(bind());
(3)將套接字設置為監(jiān)聽模式等待連接請求(listen()),;
(4)請求到來后,,接受連接請求,返回一個新的對應于此次連接的套接字(accept()),;
(5)用返回的套接字和客戶端進行通信(send()/recv()),;
(6)返回,等待另一連接請求,;
(7)關閉套接字,。
服務器端代碼:
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Text;
namespace net
{
class Program
{
static void Main(string[] args)
{
//定義接收數(shù)據(jù)長度變量
int recv;
//定義接收數(shù)據(jù)的緩存
byte[] data = new byte[1024];
//定義偵聽端口
IPEndPoint ipEnd = new IPEndPoint(IPAddress.Any, 5566);
//定義套接字類型
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//連接
socket.Bind(ipEnd);
//開始偵聽
socket.Listen(10);
//控制臺輸出偵聽狀態(tài)
Console.Write("Waiting for a client");
//一旦接受連接,創(chuàng)建一個客戶端
Socket client = socket.Accept();
//獲取客戶端的IP和端口
IPEndPoint ipEndClient = (IPEndPoint)client.RemoteEndPoint;
//輸出客戶端的IP和端口
Console.Write("Connect with {0} at port {1}", ipEndClient.Address, ipEndClient.Port);
//定義待發(fā)送字符
string welcome = "Welcome to my server";
//數(shù)據(jù)類型轉換
data = Encoding.ASCII.GetBytes(welcome);
//發(fā)送
client.Send(data, data.Length, SocketFlags.None);
while (true)
{
//對data清零
data = new byte[1024];
//獲取收到的數(shù)據(jù)的長度
recv = client.Receive(data);
//如果收到的數(shù)據(jù)長度為0,,則退出
if (recv == 0)
break;
//輸出接收到的數(shù)據(jù)
Console.Write(Encoding.ASCII.GetString(data, 0, recv));
//將接收到的數(shù)據(jù)再發(fā)送出去
client.Send(data, recv, SocketFlags.None);
}
Console.Write("Disconnect form{0}", ipEndClient.Address);
client.Close();
socket.Close();
}
}
}
4.2 客戶端編程的步驟:
(1) 創(chuàng)建套接字,;
(2) 向服務器發(fā)出連接請求(connect());
(3) 和服務器端進行通信(send()/recv()),;
(4) 關閉套接字,。
客戶端代碼:
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Text;
namespace client
{
class Program
{
static void Main(string[] args)
{
//定義發(fā)送數(shù)據(jù)緩存
byte[] data = new byte[1024];
//定義字符串,用于控制臺輸出或輸入
string input, stringData;
//定義主機的IP及端口
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEnd = new IPEndPoint(ip, 5566);
//定義套接字類型
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//嘗試連接
try
{
socket.Connect(ipEnd);
}
//異常處理
catch (SocketException e)
{
Console.Write("Fail to connect server");
Console.Write(e.ToString());
return;
}
//定義接收數(shù)據(jù)的長度
int recv = socket.Receive(data);
//將接收的數(shù)據(jù)轉換成字符串
stringData = Encoding.ASCII.GetString(data, 0, recv);
//控制臺輸出接收到的數(shù)據(jù)
Console.Write(stringData);
//定義從鍵盤接收到的字符串
input = Console.ReadLine();
//將從鍵盤獲取的字符串轉換成整型數(shù)據(jù)并存儲在數(shù)組中
data = Encoding.ASCII.GetBytes(input);
//發(fā)送該數(shù)組
socket.Send(data, data.Length, SocketFlags.None);
while (true)
{
//
//如果字符串是"exit",,退出while循環(huán)
if (input == "exit")
{
break;
}
//對data清零
data = new byte[1024];
//定義接收到的數(shù)據(jù)的長度
recv = socket.Receive(data);
//將接收到的數(shù)據(jù)轉換為字符串
stringData = Encoding.ASCII.GetString(data, 0, recv);
//控制臺輸出字符串
Console.Write(stringData);
//發(fā)送收到的數(shù)據(jù)
socket.Send(data, recv, 0);
}
Console.Write("disconnect from server");
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}
}
上述代碼實現(xiàn)了,,當連接建立之后,客戶端向服務器端發(fā)送鍵盤輸入的字符,,服務器端收到字符后,,顯示在控制臺并發(fā)送給客戶端,客戶端收到字符后,,顯示在控制臺并再次發(fā)送給服務器端,,如此循環(huán)。
五,、實驗結果
先后運行服務器端程序和客戶端程序,,控制臺界面如下:
圖1 服務器端控制臺
當連接建立后,服務器端控制臺顯示等待客戶端的狀態(tài)"Waiting for a client",,并打印出連接信息,。
圖2 客戶端控制臺
當連接建立后,客戶端收到來自服務器端發(fā)送的字符串"Welcome to my server",。
之后,客戶端通過鍵盤發(fā)送數(shù)據(jù),二者循環(huán)接收并發(fā)送,,控制臺分別如下:
圖3 服務器控制臺
圖4 客戶端控制臺
六,、幾點說明
6.1 傳輸速度
(1) 增大發(fā)送和接收的數(shù)組可提升傳輸速度,即增加一次實際發(fā)送數(shù)據(jù)的數(shù)量可以提高傳輸速度,,但數(shù)組中數(shù)據(jù)的個數(shù)也不能一味的增大,。需要說明的,由于地層MIT的限制,,底層具體實現(xiàn)的時候每次發(fā)送的數(shù)據(jù)仍是不超過1510個的,。
(2) 將控制臺界面最小化后,速度也會有翻倍的提升,。
6.2 MFC的轉換
為了使傳輸協(xié)議更有可觀性和使用性,,通常做成MFC的樣式,具體的使用已在"基于TCP協(xié)議的網絡攝像頭的設計與實現(xiàn)"應用,。
|