Socket
命名空間:System.Net.Sockets
服務(wù)器端:
static void Main(string[] args)
{
// socket
Socket listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// bind
IPAddress ipAdr = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEP = new IPEndPoint(ipAdr, 1234);
listenfd.Bind(ipEP);
// listen
listenfd.Listen(0);
//
while (true)
{
// accept
Socket connfd = listenfd.Accept();
// receive
byte[] readBuff = new byte[1024];
int count = connfd.Receive(readBuff);
string str = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
Console.WriteLine("[服務(wù)器接收:]" + str);
// send
byte[] bytes = System.Text.Encoding.Default.GetBytes("serv echo " + str);
connfd.Send(bytes);
}
}
AddressFamily:地址簇,指明是使用IPv4還是IPv6
SocketType:套接字類型其屏,Stream支持可靠、雙向惧眠、基于連接的字節(jié)流详囤,既不重復(fù)數(shù)據(jù),也不保留邊界
ProtocolType:協(xié)議
Socket.Bind(IPEndPoint):給Socket綁定IP和端口
Socket.Listen(int backlog):開啟監(jiān)聽肋拔,等待客戶端連接锈津,參數(shù)指定隊列中最多可容納等待接受的連接數(shù),0表示不限制
Socket.Accept:開啟監(jiān)聽后只损,服務(wù)器調(diào)用Accept接受客戶端連接
Receive:接收客戶端數(shù)據(jù)一姿,receive帶有一個byte[]類型參數(shù),它將存儲接收到的數(shù)據(jù)跃惫,返回值指明接收到的數(shù)據(jù)的長度
Send:發(fā)送數(shù)據(jù)叮叹,接受一個byte[]類型的參數(shù),指明要發(fā)送的內(nèi)容
客戶端:
Socket socket;
public InputField hostText;
public InputField portText;
public Text ipText;
public Text contentText;
byte[] readBuff = new byte[1024];
public void Connection()
{
// socket
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// connect
string host = hostText.text;
int port = int.Parse(portText.text);
socket.Connect(host, port);
ipText.text = socket.LocalEndPoint.ToString();
// send
string str = "hello world";
byte[] bytes = System.Text.Encoding.Default.GetBytes(str);
socket.Send(bytes);
// receive
int count = socket.Receive(readBuff);
str = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
contentText.text = str;
socket.Close();
}
粘包分包處理:
處理粘包分包的一種方法是在每個數(shù)據(jù)包前面加上長度字節(jié)爆存。每次接受到數(shù)據(jù)后蛉顽,先讀取長度字節(jié),如果緩沖區(qū)的數(shù)據(jù)長度大于要提取的字節(jié)數(shù)先较,則取出相應(yīng)的字節(jié)携冤,負(fù)責(zé)等待下一次數(shù)據(jù)接收。
- Connect連接類:
public class Connect
{
public const int BUFFER_SIZE = 1024;
public Socket socket;
public bool isuse = false;
public byte[] readBuff = new byte[BUFFER_SIZE];
public int bufferCount = 0;
public byte[] lenBytes = new byte[sizeof(int)];
public int msgLength = 0;
public Connect()
{
readBuff = new byte[BUFFER_SIZE];
}
public void Init(Socket socket)
{
this.socket = socket;
isuse = true;
bufferCount = 0;
}
public int BuffRemain()
{
return BUFFER_SIZE - bufferCount;
}
public string GetAdress()
{
if (!isuse)
return "無法獲取地址";
return socket.RemoteEndPoint.ToString();
}
public void Close()
{
if (!isuse)
return;
Console.WriteLine("[斷開鏈接]" + GetAdress());
socket.Shutdown(SocketShutdown.Both);
socket.Close();
isuse = false;
}
}
- ReceiveCb的粘包分包處理:ReceiveCb是接收數(shù)據(jù)的回調(diào)闲勺,它通過socket.EndReceive獲取接收到數(shù)據(jù)的字節(jié)數(shù)count曾棕。connect.buffCount指向緩沖區(qū)的數(shù)據(jù)長度,接收數(shù)據(jù)緩沖區(qū)數(shù)據(jù)增加時菜循,需要給buffCount加上count告匠。
ReceiveCb的實現(xiàn)如下:
public void ReceiveCb(IAsyncResult ar)
{
Connect connect = (Connect)ar.AsyncState;
try
{
int count = connect.socket.EndReceive(ar);
if (count <= 0)
{
Console.WriteLine(connect.GetAdress()+"斷開連接");
connect.Close();
return;
}
connect.bufferCount += count;
ProcessData(connect);
connect.socket.BeginReceive(connect.readBuff, connect.bufferCount, connect.BuffRemain(), SocketFlags.None, ReceiveCb, connect);
}
catch(Exception e)
{
Console.WriteLine(connect.GetAdress() + "斷開連接");
connect.Close();
}
}
void ProcessData(Connect connect)
{
if (connect.bufferCount < sizeof(int))
return;
// 消息長度
Array.Copy(connect.readBuff, connect.lenBytes, sizeof(int));
connect.msgLength = BitConverter.ToInt32(connect.lenBytes, 0);
if (connect.bufferCount < connect.msgLength + sizeof(int))
return;
// 處理消息
string str = System.Text.Encoding.UTF8.GetString(connect.readBuff, sizeof(int), connect.msgLength);
Console.WriteLine("收到消息" + str);
int count = connect.bufferCount - sizeof(int) - connect.msgLength;
// 消除已處理的消息
Array.Copy(connect.readBuff, sizeof(int) + connect.msgLength, connect.readBuff, 0, count);
connect.bufferCount = count;
if (connect.bufferCount > 0)
{
ProcessData(connect);
}
}
- 發(fā)送消息:需要組裝消息長度和消息內(nèi)容堡距,然后一起發(fā)送
void Send(Connect connect,string str)
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(str);
byte[] length = BitConverter.GetBytes(bytes.Length);
byte[] sendbuff = length.Concat(bytes).ToArray();
try
{
connect.socket.BeginSend(sendbuff, 0, sendbuff.Length, SocketFlags.None, null, null);
}
catch(Exception e)
{
Console.WriteLine("發(fā)送消息:" + e.Message);
}
}