看了系列一 我們開啟了對socket tcp的監聽狀態,那么這一章我們來講解怎么創建socket的通信代碼
我新建一個類 TSocketBase
public abstract class TSocketBase
{
//封裝socket
internal Socket _Socket;
//回調
private AsyncCallback aCallback;
//接受數據的緩沖區
private byte[] Buffers;
//標識是否已經釋放
private volatile bool IsDispose;
//10K的緩沖區空間
private int BufferSize = 10*1024;
//收取消息狀態碼
private SocketError ReceiveError;
//發送消息的狀態碼
private SocketError SenderError;
//每一次接受到的字節數
private int ReceiveSize = 0;
//接受空消息次數
private byte ZeroCount = 0;
public abstract void Receive(byte[] rbuff);
public void SetSocket()
{
this.aCallback = new AsyncCallback(this.ReceiveCallback);
this.IsDispose = false;
this._Socket.ReceiveBufferSize = this.BufferSize;
this._Socket.SendBufferSize = this.BufferSize;
this.Buffers = new byte[this.BufferSize];
}
/// <summary>
/// 關閉並釋放資源
/// </summary>
/// <param name="msg"></param>
public void Close(string msg)
{
if (!this.IsDispose)
{
this.IsDispose = true;
try
{
try
{
this._Socket.Close();
}
catch
{
}
IDisposable disposable = this._Socket;
if (disposable != null)
{
disposable.Dispose();
}
this.Buffers = null;
GC.SuppressFinalize(this);
}
catch (Exception)
{
}
}
}
/// <summary>
/// 遞歸接收消息方法
/// </summary>
internal void ReceiveAsync()
{
try
{
if (!this.IsDispose && this._Socket.Connected)
{
this._Socket.BeginReceive(this.Buffers, 0, this.BufferSize, SocketFlags.None, out SenderError,
this.aCallback, this);
CheckSocketError(ReceiveError);
}
}
catch (System.Net.Sockets.SocketException)
{
this.Close("鏈接已經被關閉");
}
catch (System.ObjectDisposedException)
{
this.Close("鏈接已經被關閉");
}
}
/// <summary>
/// 接收消息回調函數
/// </summary>
/// <param name="iar"></param>
private void ReceiveCallback(IAsyncResult iar)
{
if (!this.IsDispose)
{
try
{
//接受消息
ReceiveSize = _Socket.EndReceive(iar, out ReceiveError);
//檢查狀態碼
if (!CheckSocketError(ReceiveError) && SocketError.Success == ReceiveError)
{
//判斷接受的字節數
if (ReceiveSize > 0)
{
byte[] rbuff = new byte[ReceiveSize];
Array.Copy(this.Buffers, rbuff, ReceiveSize);
this.Receive(rbuff);
//重置連續收到空字節數
ZeroCount = 0;
//繼續開始異步接受消息
ReceiveAsync();
}
else
{
ZeroCount++;
if (ZeroCount == 5)
{
this.Close("錯誤鏈接");
}
}
}
}
catch (System.Net.Sockets.SocketException)
{
this.Close("鏈接已經被關閉");
}
catch (System.ObjectDisposedException)
{
this.Close("鏈接已經被關閉");
}
}
}
/// <summary>
/// 錯誤判斷
/// </summary>
/// <param name="socketError"></param>
/// <returns></returns>
private bool CheckSocketError(SocketError socketError)
{
switch ((socketError))
{
case SocketError.SocketError:
case SocketError.VersionNotSupported:
case SocketError.TryAgain:
case SocketError.ProtocolFamilyNotSupported:
case SocketError.ConnectionAborted:
case SocketError.ConnectionRefused:
case SocketError.ConnectionReset:
case SocketError.Disconnecting:
case SocketError.HostDown:
case SocketError.HostNotFound:
case SocketError.HostUnreachable:
case SocketError.NetworkDown:
case SocketError.NetworkReset:
case SocketError.NetworkUnreachable:
case SocketError.NoData:
case SocketError.OperationAborted:
case SocketError.Shutdown:
case SocketError.SystemNotReady:
case SocketError.TooManyOpenSockets:
this.Close(socketError.ToString());
return true;
}
return false;
}
/// <summary>
/// 發送消息方法
/// </summary>
internal int SendMsg(byte[] buffer)
{
int size = 0;
try
{
if (!this.IsDispose)
{
size = this._Socket.Send(buffer, 0, buffer.Length, SocketFlags.None, out SenderError);
CheckSocketError(SenderError);
}
}
catch (System.ObjectDisposedException)
{
this.Close("鏈接已經被關閉");
}
catch (System.Net.Sockets.SocketException)
{
this.Close("鏈接已經被關閉");
}
buffer = null;
return size;
}
}
上面我們事先了socket的異步接受消息,和同步發送消息已經關閉釋放資源代碼
接受消息net底層提供的接受消息的方法有很多,為什么我們要選擇上面所寫的呢?那是為了兼容U3D,silverlight, wpf, wp, wf,等程序可執行,不在重復做相同工作。
現在我們來創建一個實現類 TSocketClient
public class TSocketClient : TSocketBase
{
/// <summary>
/// 是否是服務器端的資源
/// </summary>
private bool isServer = false;
/// <summary>
/// 客戶端主動請求服務器
/// </summary>
/// <param name="ip"></param>
/// <param name="port"></param>
public TSocketClient(string ip = "127.0.0.1", int port = 9527)
{
isServer = false;
this._Socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this._Socket.Connect(ip, port);
this.SetSocket();
this.ReceiveAsync();
}
/// <summary>
/// 這個是服務器收到有效鏈接初始化
/// </summary>
/// <param name="socket"></param>
public TSocketClient(Socket socket)
{
isServer = true;
this._Socket = socket;
this.SetSocket();
this.ReceiveAsync();
}
/// <summary>
/// 收到消息后
/// </summary>
/// <param name="rbuff"></param>
public override void Receive(byte[] rbuff)
{
Console.WriteLine("Receive Msg:" + System.Text.UTF8Encoding.Default.GetString(rbuff));
if (isServer)
{
this.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Client!"));
}
}
}
因為是測試示例,所以我把服務器和客戶端實現類寫成了,只是用來不同的構造函數來區分,是客戶端還是服務器的標識
接下來我們測試一下代碼
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 TCPListener tcp = new TCPListener();
6 TSocketClient client = new TSocketClient();
7 client.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Server!"));
8 Console.ReadLine();
9 }
10 }

運行結果看出,我們連接成功並且發送消息成功。

