最近开始自学socket编程,从网上找不到好的教程,索性搬了个梯只,
刚开始学习,水平有限,见谅
窗口布局
Asset
这里我们既当Server也当Client,所以把两个代码都加载上,放到Server这个空GameObject上
这里聊天信息弹出的思路是在chatWindows上加上
然后接受到聊天信息之后将data放到asset下的prefab里实例化到chatWindows的子物体上,有一个自动排版在里面。
然后就是代码部分了
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System;
using System.IO;
public class Server : MonoBehaviour {
private List clients; //所有的客户端的集合
private List disconnectList; //掉线的客户端的集合
public int port = 6321; //端口
private TcpListener server; //定义一个端口监听对象
private bool serverStarted; //判断服务器是否开启的判断值
private void Start()
{
clients = new List();
disconnectList = new List();
try
{
server = new TcpListener(IPAddress.Any, port);
server.Start(); //应该是一个类似线程的东西,个人感觉TcpListener本身就包含了一个线程
StartListening(); //开始监听
serverStarted = true;
Debug.Log("Server has been started on port" + port.ToString());
}
catch (Exception ex)
{
Debug.Log("Socket error:"+ex.Message);
}
}
private void Update()
{
if (!serverStarted)
return;
foreach (ServerClient c in clients)
{
//客户端是否仍然在线?
if (!IsConnected(c.tcp))
{
c.tcp.Close();
disconnectList.Add(c);
continue;
}
//检查客户端发送过来的数据
else
{
NetworkStream s = c.tcp.GetStream();
if (s.DataAvailable)
{
StreamReader reader = new StreamReader(s, true);
string data = reader.ReadLine();
if (data != null)
OnIncomingData(c, data); //对数据的回调函数
}
}
}
for (int i = 0; i < disconnectList.Count - 1; i++)
{
Broadcast(disconnectList[i].clientName + " has disconnected !",clients);
clients.Remove(disconnectList[i]);
disconnectList.RemoveAt(i);
}
}
private void OnIncomingData(ServerClient c, string data)
{
if (data.Contains("%NAME")) //第一次握手,得到一个包含%NAME|[clientName]的字符串
{
c.clientName = data.Split('|')[1]; //通过|将客户端的名字单独分割出来
Broadcast(c.clientName + " has connected !",clients); //广播
return; //握手完了还没开始聊天,先结束掉
}
Broadcast(c.clientName+" : "+data,clients); //握手之后开始广播发送的聊天信息
}
private void StartListening()
{
server.BeginAcceptTcpClient(AcceptTcpClient,server);
}
private bool IsConnected(TcpClient c)
{
try
{
if (c != null && c.Client != null && c.Client.Connected)
{
if (c.Client.Poll(0, SelectMode.SelectRead))
{
return !(c.Client.Receive(new byte[1],SocketFlags.Peek)==0);
}
return true;
}
else
return false;
}
catch
{
return false;
}
} //检查是否仍然在线
private void AcceptTcpClient(IAsyncResult ar)
{
TcpListener listener = (TcpListener)ar.AsyncState;
clients.Add(new ServerClient(listener.EndAcceptTcpClient(ar)));
StartListening();
//Send a message to everyone,say someone has connected
Broadcast("%NAME",new List() { clients[clients.Count-1]});
}
private void Broadcast(string data, List cl)
{
foreach (ServerClient c in cl)
{
try
{
StreamWriter writer = new StreamWriter(c.tcp.GetStream());
writer.WriteLine(data); //
writer.Flush(); //应该是清楚writer的buffer,将数据发送出去
}
catch (Exception e)
{
Debug.Log("Write error :" + e.Message + "to client" + c.clientName);
}
}
}
}
public class ServerClient
{
public TcpClient tcp;
public string clientName;
public ServerClient(TcpClient clientSocket)
{
clientName = "Guest";
tcp = clientSocket; //连接上
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using UnityEngine;
using UnityEngine.UI;
public class Client : MonoBehaviour {
public GameObject chatContainer;
public GameObject messagePrefab;
public string clientName;
private bool socketReady;
private TcpClient socket;
private NetworkStream stream;
private StreamWriter writer;
private StreamReader reader;
public void ConnectToServer()
{
#region already connected,ignore this function
if (socketReady)
return;
#endregion
#region Default host / port values
string host = "127.0.0.1";
int port = 6321;
#endregion
#region Overwrite default host / port values,if there is something in those boxes
string h;
int p;
h = GameObject.Find("HostInput").GetComponent().text;
if (h != "")
host = h;
int.TryParse(GameObject.Find("PortInput").GetComponent().text,out p);
if (p != 0)
port = p;
#endregion
//Create the socket
try
{
socket = new TcpClient(host, port);
stream = socket.GetStream(); //得到socket中获取到的数据流
writer = new StreamWriter(stream);
reader = new StreamReader(stream); //初始化读和写
socketReady = true;
}
catch(Exception e)
{
Debug.Log("Socket error:" + e.Message);
}
}
private void OnIncomingData(string data)
{
if (data == "%NAME") //(第一次)如果接受到的信息是%NAME,之后接受到的信息将不再含有%NAME
{
Send("%NAME|" + clientName); //将收到的信息"%NAME"转换成 "%NAME|[clientName]"
return;
}
GameObject go = Instantiate(messagePrefab, chatContainer.transform)as GameObject;
go.GetComponentInChildren().text = data; //将接受到的聊天信息打印出来
}
private void Send(string data)
{
if (!socketReady)
return;
writer.WriteLine(data);
writer.Flush();
}
public void OnSendButton()
{
string message = GameObject.Find("SendInput").GetComponent().text;
Send(message);
} //点击按钮的回调函数
private void Update()
{
if (socketReady)
{
if (stream.DataAvailable)
{
string data = reader.ReadLine();
if (data != null)
OnIncomingData(data);
}
}
}
private void CloseSocket()
{
if (!socketReady)
return;
writer.Close();
reader.Close();
socket.Close();
socketReady = false;
}
private void OnApplicationQuit() //游戏退出时的回调函数
{
CloseSocket();
}
private void OnDisable()
{
CloseSocket();
}
}
运行结果