一、第一步开始连接
- 创建socket
//创建Tcp方式连接 AddressFamily.InterNetworkV6 可以设置成支持IPv6 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- 根据ip和port转换成IpEndPoint
IPAddress servAD = null; try { if (url.Contains(".com") || url.Contains(".net") || url.Contains(".cn")) { IPAddress[] IPs = Dns.GetHostAddresses(url); //这里同步解析域名,也可以改为BeginGetHostAddresses异步方式 servAD = IPs[0]; //一个域名可以对应多个ip这里选第一个 } else { servAD = IPAddress.Parse(url); //"192.168.1.1" } } catch (Exception e) { Debug.LogError("can not parse url:" + e.ToString()); } iPEndPoint = new IPEndPoint(servAD, port);
- 开始连接
public void Connnet() { try { socket.BeginConnect(iPEndPoint, ConnectCallback, socket); } catch (Exception e) { Debug.LogError("can not Connect:" + e.ToString()); } } private void ConnectCallback(IAsyncResult ar) { try { socket.EndConnect(ar); //or socket from [(Socket)ar.AsyncState] ConnectAction?.Invoke(true); Receive(true, 0, HeaderLength); } catch (Exception e) { ConnectAction?.Invoke(false); Debug.LogError("Connect Callback fail :" + e.ToString()); } }
二、发送消息
使用BeginSend和EndSend方法异步发送。其中判断实际发送长度小于要发送昌都时,递归再次发送
public void Send(byte[] data)
{
lock (gate)
{
if (!isSending)
{
isSending = true;
DoSend(data, 0);
}
else
{
requests.Enqueue(data);
}
}
}
private void DoSend(byte[] buf, int offset)
{
try
{
socket.BeginSend(buf, offset, buf.Length - offset, SocketFlags.None, asyncResult => {
int sentBytes = 0;
try
{
sentBytes = socket.EndSend(asyncResult);
}
catch (Exception ex)
{
Debug.LogError("socket send end error" + ex.ToString());
Close();
return;
}
if (sentBytes < buf.Length - offset)
{
DoSend(buf, offset + sentBytes);
}
else
{
byte[] pendingBuf = null;
lock (gate)
{
if (requests.Count > 0)
{
pendingBuf = requests.Dequeue();
}
else
{
isSending = false;
}
}
if (pendingBuf != null)
{
DoSend(pendingBuf, 0);
}
}
}, null);
}
catch (Exception ex)
{
Debug.LogError("socket send error" + ex.ToString());
Close();
}
}
三、接收消息
- 接收消息时,会存在实际读取值小于需要读取值的情况,需要递归多次读取。过程中还做了粘包处理先用4个字节长度存储真实消息长度方式。
private void DoSend(byte[] buf, int offset)
{
try
{
socket.BeginSend(buf, offset, buf.Length - offset, SocketFlags.None, asyncResult => {
int sentBytes = 0;
try
{
sentBytes = socket.EndSend(asyncResult);
}
catch (Exception ex)
{
Debug.LogError("socket send end error" + ex.ToString());
Close();
return;
}
if (sentBytes < buf.Length - offset)
{
DoSend(buf, offset + sentBytes);
}
else
{
byte[] pendingBuf = null;
lock (gate)
{
if (requests.Count > 0)
{
pendingBuf = requests.Dequeue();
}
else
{
isSending = false;
}
}
if (pendingBuf != null)
{
DoSend(pendingBuf, 0);
}
}
}, null);
}
catch (Exception ex)
{
Debug.LogError("socket send error" + ex.ToString());
Close();
}
}
private void Receive(bool isHead, int offset, int size, byte[] buf = null)
{
if (buf == null)
{
buf = new byte[size];
}
try
{
socket.BeginReceive(buf, offset, size, SocketFlags.None, asyncResult => {
int length;
try
{
length = socket.EndReceive(asyncResult); //return real read length
}
catch (Exception ex)
{
Debug.LogError("socket recive end fail:" + ex.ToString());
Close();
return;
}
if (length == 0)
{
Close();
return;
}
if (length < size)
{
Receive(isHead, offset + length, size - length, buf);
return;
}
if (isHead)
{
//得到的网络字节序长度转换成主机字节序的长度,服务端返回的长度包含头的长度,所以减去头的大小
size = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buf, 0));
}
else
{
AddResponse(buf);
size = HeaderLength;
}
Receive(!isHead, 0, size);
}, null);
}
catch (Exception ex)
{
Debug.LogError("socket recive fail:" + ex.ToString());
Close();
}
}
四、关闭socket
try
{
socket.Shutdown(SocketShutdown.Both);
}
catch (Exception ex)
{
Debug.LogError("socket Shutdown fail" + ex.ToString());
}
try
{
socket.Close();
}
catch (Exception ex)
{
Debug.LogError("socket Close fail" + ex.ToString());
}
socket = null;