学习Unity有一点时间了,之前学的都是做客户端的一些内容,现在开始学习联网。我的这个是在观看了 Siki 的教学内容来做的,也有自己的一点点小小的改动在里面。纯粹用于练手了。
因为本人也是小白一枚,所以,有错误的地方或者更好的实现方法,也希望有大神能帮忙指正,多谢!
整体过程分为两部分:构建服务端、构建客户端。
服务端:
大概思路:
1. 声明Socket连接以及绑定IP和端口,这里面使用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
namespace ServerApplication
{
class Program
{
public static string IP;
public static int Port;
static List<Client> clientList = new List<Client>();
static Socket serverSocket;
static void Main(string[] args)
{
//绑定IP和端口
BindIPAndPort();
//
while (true)
{
Socket clientSocket = serverSocket.Accept();
Client client = new Client(clientSocket);
clientList.Add(client);
Console.WriteLine("一台主机进入连接");
}
}
/// <summary>
/// 广播数据
/// </summary>
public static void BroadcostMSG(string s)
{
List<Client> NotConnectedList = new List<Client>();
foreach (var item in clientList)
{
if(item.IsConnected)
{
item.SendMSG(s);
}
else
{
NotConnectedList.Add(item);
}
}
foreach (var item in NotConnectedList)
{
clientList.Remove(item);
}
}
/// <summary>
/// 绑定IP和端口
/// </summary>
public static void BindIPAndPort()
{
//创建一个serverSocket
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//声明IP和端口
Console.WriteLine("输入IP地址:");
IP = Console.ReadLine();
string ipStr = IP;
Console.WriteLine("请输入端口:");
Port = int.Parse(Console.ReadLine());
int port = Port;
IPAddress serverIp = IPAddress.Parse(ipStr);
EndPoint serverPoint = new IPEndPoint(serverIp, port);
//socket和ip进行绑定
serverSocket.Bind(serverPoint);
//监听最大数为100
serverSocket.Listen(100);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Threading;
namespace ServerApplication
{
class Client
{
public Socket clientSocket;
//声明一个线程用于接收信息
Thread t;
//接收信息所用容器
byte[] data = new byte[1024];
//构造函数
public Client(Socket s)
{
clientSocket = s;
t = new Thread(ReceiveMSG);
t.Start();
}
/// <summary>
/// 接收数据
/// </summary>
void ReceiveMSG()
{
while(true)
{
if (clientSocket.Poll(10,SelectMode.SelectRead))
{
break;
}
data = new byte[1024];
int length = clientSocket.Receive(data);
string message = Encoding.UTF8.GetString(data, 0, length);
Program.BroadcostMSG(message);
Console.WriteLine("收到消息:" + message);
}
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="s"></param>
public void SendMSG(string message)
{
byte[] data = Encoding.UTF8.GetBytes(message);
clientSocket.Send(data);
}
//判断此Client对象是否在连接状态
public bool IsConnected
{
get { return clientSocket.Connected; }
}
}
}
2.客户端
a.UI界面
UI界面是使用UGUI实现的
登录用户可以自己取名进行登录(发言时用于显示),使用时需要输入服务端的IP地址和端口号
下面是聊天室的页面,在输入框内输入要发送的消息,点击Send,将信息发送出去
这是服务端心事的信息
b.关于客户端的脚本
(1)这是ClientManager,负责与服务端进行连接,通信
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System.Net;
using System.Text;
using UnityEngine.UI;
using System.Threading;
public class ClientManager : MonoBehaviour
{
//ip:192.168.1.7
public string ipAddressstr;
public int port;
public Text ipTextToShow;
//Socket
private Socket ClientServer;
//文本输入框
public InputField inputTxt;
public string inputMSGStr;
//接收
Thread t;
public Text receiveTextCom;
public string message;
// Use this for initialization
void Start()
{
ipTextToShow.text = ipAddressstr;
// ConnectedToServer();
}
// Update is called once per frame
void Update()
{
if (message != null && message != "")
{
receiveTextCom.text = receiveTextCom.text + "\n" + message;
message = "";
}
}
/// <summary>
/// 连接服务器
/// </summary>
public void ConnectedToServer()
{
ClientServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//声明IP地址和端口
IPAddress ServerAddress = IPAddress.Parse(ipAddressstr);
EndPoint ServerPoint = new IPEndPoint(ServerAddress, port);
ipAddressstr = IpInfo.ipStr;
port = IpInfo.portStr;
//开始连接
ClientServer.Connect(ServerPoint);
t = new Thread(ReceiveMSG);
t.Start();
}
/// <summary>
/// 接收消息
/// </summary>
/// <returns>“string”</returns>
void ReceiveMSG()
{
while (true)
{
if (ClientServer.Connected == false)
{
break;
}
byte[] data = new byte[1024];
int length = ClientServer.Receive(data);
message = Encoding.UTF8.GetString(data, 0, length);
//Debug.Log("有消息进来");
}
}
/// <summary>
/// 发送string类型数据
/// </summary>
/// <param name="input"></param>
public void SendMSG()
{
Debug.Log("button Clicked");
//message = "我:" + inputTxt.text;
inputMSGStr = inputTxt.text;
byte[] data = Encoding.UTF8.GetBytes(IpInfo.name+":"+inputMSGStr);
ClientServer.Send(data);
}
private void OnDestroy()
{
ClientServer.Shutdown(SocketShutdown.Both);
ClientServer.Close();
}
private void OnApplicationQuit()
{
OnDestroy();
}
}
(2)SceneManager,用于场景切换,这里只是利用GameObject进行SetActive()来实现,并不是创建了单独的Scene进行管理。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SceneManager : MonoBehaviour {
public GameObject loginPanel;
public GameObject communicatingPanel;
// Use this for initialization
public void OnSwitch()
{
loginPanel.SetActive(false);
communicatingPanel.SetActive(true);
}
}
(3)LogInPanel和IPInfo,一个挂载在登录界面上,一个是数据模型,用于存储数据。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LogInPanel : MonoBehaviour {
public Text nameInputTxt;
public Text ipInputTxt;
public Text portInputTxt;
//private string name;
//private string ipStr;
//private string portStr;
public void OnLogInClick()
{
IpInfo.name = nameInputTxt.text;
IpInfo.ipStr = ipInputTxt.text;
IpInfo.portStr = int.Parse(portInputTxt.text);
}
}
public static class IpInfo {
public static string name;
public static string ipStr;
public static int portStr;
}
总结:第一次写学习博,还有很多地方要学习啊。
留待解决的问题:此聊天室只能用于局域网以内,广域网就无法实现通信了,还要看看怎么实现远程的一个通信,不然这个就没有存在的意义了。