参考
《unity3D 网络游戏实战》第二章 异步与多路复用
《socket中accept()函数的理解》—— https://www.cnblogs.com/cooperstuff/archive/2012/03/21/2410494.html
这里需要注意的:
unity是单线程引擎,在其它线程内不可以调用unity API,也无法修改unity UI,所以这里修改ui的部分,就放在了update函数中.
这里需要理解的是:
服务端与客户端的交互,对于服务端来说并不是直接使用服务端的用来监听和应答的Socket实例向客户端发送数据,接收数据。
服务端向客户端发送数据:
1.如果是同步方式
使用服务端Socket实例,调用Accept()方法, Accept()方法返回一个新的Socket对象,该Socket对象用来处理客户端的数据
Socket listenfd = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp )
........
Socket connfd = listenfd.Accept( );
......
connfd.Send( sendBytes )
在服务端代码中:
对于服务器,它有一个监听Socket,也就是上面代码中的listenfd ,listenfd 用来监听(Listen)和应答(Accept)客户端的连接。
对于客户端,它有一个listenfd.Accept( )返回的Socket实例 connfd用来处理客户端数据
2.如果是异步方式
异步方式,见下面服务端代码, 使用 listenfd.EndAccept(ar) 返回一个处理客户端数据的socket.
客户端:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Net.Sockets;
using System;
using System.Text;
public class SocketClient : MonoBehaviour
{
public InputField m_InputField;
public Text m_text;
Socket m_socket;
//接收缓冲区
byte[] m_readBuff = new byte[1024];
string m_recvStr = "";
public void Connection()
{
m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_socket.BeginConnect("127.0.0.1", 8888, ConnectCallback, m_socket);
}
//Connect回调
public void ConnectCallback(IAsyncResult ar)
{
try
{
Socket socket = (Socket)ar.AsyncState;
socket.EndConnect(ar);
Debug.Log("Socket连接成功");
socket.BeginReceive(m_readBuff, 0, 1024, 0, ReceiveCallback, socket);
}
catch (SocketException ex)
{
Debug.Log("Socket连接失败" + ex.ToString());
}
}
//Receive 回调
public void ReceiveCallback(IAsyncResult ar)
{
try
{
Debug.Log("ReceiveCallback");
Socket socket = (Socket)ar.AsyncState;
int count = socket.EndReceive(ar);
Debug.Log("数据长度" + count);
m_recvStr = Encoding.Default.GetString(m_readBuff, 0, count);
socket.BeginReceive(m_readBuff, 0, 1024, 0,
ReceiveCallback, socket);
Debug.Log( "接收数据成功" + m_recvStr );
//m_text.text = m_recvStr;//由于使用了其他线程所以无法修改UI
}
catch (SocketException ex)
{
Debug.Log("Socket接收失败" + ex.ToString());
}
}
public void Send()
{
string sendStr = m_InputField.text;
byte[] sendBytes = Encoding.Default.GetBytes(sendStr);
m_socket.BeginSend(sendBytes, 0, sendBytes.Length, 0, SendCallBack, m_socket);
}
public void SendCallBack( IAsyncResult ar )
{
try
{
Socket socket = (Socket)ar.AsyncState;
int count = socket.EndSend(ar);
Debug.Log( "Socket发送数据成功" );
}
catch ( SocketException ex )
{
Debug.Log("Socket发送失败" + ex.ToString());
}
}
private void Update()
{
m_text.text = m_recvStr;
}
}
服务端:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Chapter_Server
{
class ClientState
{
public Socket socket;
public byte[] readBuff = new byte[1024];
}
class Program
{
//监听 Socket
static Socket listenfd;
//客户端Socket及状态信息
static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
//创建Socket
listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定
IPAddress iPAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, 8888);
listenfd.Bind(iPEndPoint);
//监听
listenfd.Listen(0);
Console.WriteLine();
//开始Accept
listenfd.BeginAccept(AcceptCallback, listenfd);
//等待
Console.ReadLine();
}
public static void AcceptCallback( IAsyncResult ar )
{
try
{
Console.WriteLine("[服务器]接收");
Socket listenfd = (Socket) ar.AsyncState;
Socket clientfd = listenfd.EndAccept(ar);
//为连接分配ClientState, 并把它添加到clients列表
ClientState state = new ClientState();
state.socket = clientfd;
clients.Add(clientfd, state);
//接收数据
clientfd.BeginReceive(state.readBuff, 0, 1024, 0,
ReceiveCallback, state);
//继续下一次接受
listenfd.BeginAccept(AcceptCallback, listenfd);
}
catch ( SocketException ex )
{
Console.WriteLine( "Socket接受失败" + ex.ToString() );
}
}
public static void ReceiveCallback( IAsyncResult ar )
{
try
{
ClientState state = (ClientState) ar.AsyncState;
//client端连接进来通过socket实例clientfd与客户端进行交互
Socket clientfd = state.socket;
int count = clientfd.EndReceive(ar);
//客户端关闭
if( count==0 )
{
clientfd.Close();
clients.Remove(clientfd);
Console.WriteLine("关闭Socket");
return;
}
string recvStr = Encoding.Default.GetString(state.readBuff, 0, count);
byte[] sendBytes = Encoding.Default.GetBytes("echo" + recvStr);
clientfd.Send(sendBytes);
clientfd.BeginReceive(state.readBuff, 0, 1024, 0,
ReceiveCallback, state);
Console.WriteLine( "发送数据{0}"+ recvStr);
}
catch( SocketException ex )
{
Console.WriteLine("Socket接收数据失败" + ex.ToString());
}
}
}
}