Socket
命名空间:System.Net.Sockets
服务器端:
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("[服务器接收:]" + str);
// send
byte[] bytes = System.Text.Encoding.Default.GetBytes("serv echo " + str);
connfd.Send(bytes);
}
}
AddressFamily:地址簇,指明是使用IPv4还是IPv6
SocketType:套接字类型,Stream支持可靠、双向、基于连接的字节流,既不重复数据,也不保留边界
ProtocolType:协议
Socket.Bind(IPEndPoint):给Socket绑定IP和端口
Socket.Listen(int backlog):开启监听,等待客户端连接,参数指定队列中最多可容纳等待接受的连接数,0表示不限制
Socket.Accept:开启监听后,服务器调用Accept接受客户端连接
Receive:接收客户端数据,receive带有一个byte[]类型参数,它将存储接收到的数据,返回值指明接收到的数据的长度
Send:发送数据,接受一个byte[]类型的参数,指明要发送的内容
客户端:
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();
}
粘包分包处理:
处理粘包分包的一种方法是在每个数据包前面加上长度字节。每次接受到数据后,先读取长度字节,如果缓冲区的数据长度大于要提取的字节数,则取出相应的字节,负责等待下一次数据接收。
- 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是接收数据的回调,它通过socket.EndReceive获取接收到数据的字节数count。connect.buffCount指向缓冲区的数据长度,接收数据缓冲区数据增加时,需要给buffCount加上count。
ReceiveCb的实现如下:
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);
}
}
- 发送消息:需要组装消息长度和消息内容,然后一起发送
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("发送消息:" + e.Message);
}
}