效果展示

一个局域网内的聊天室,一个客户端发送了信息之后,服务端将其广播给当前连接的所有客户端。

服务端部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Unity聊天室服务端
{
class Client
{
private Socket clientSkt;
private Thread t;
private byte[] rcvData;
private string massage;


public Client(Socket client)
{
this.clientSkt = client;
t = new Thread(ReceiveData);
t.Start();
rcvData = new byte[1024];
Console.WriteLine("一个客户端已连接");
}


public bool Connected { get { return clientSkt.Connected; } }
/*connected返回的只是服务器是否断开和客户端的连接
*如果客户端单方断开了连接,这里的connected依然是true
* 所以要用poll来判断是否处于连通状态
*/


/// <summary>
/// 接受客户端发来的信息,并调用广播方法
/// </summary>
private void ReceiveData()
{
while (true)
{

if (clientSkt.Poll(10, SelectMode.SelectRead))
{

Program.accptClientList.Remove(this);
clientSkt.Close();
Console.WriteLine("一条连接已中断");
break;
}
else
{
int lenth = clientSkt.Receive(rcvData);
massage = Encoding.UTF8.GetString(rcvData, 0, lenth);
Console.WriteLine("服务端收到了一条消息:" + massage);
Program.BroadcastMsg(massage);
}
}
}
/// <summary>
/// 发送消息给该客户端
/// </summary>
/// <param name="msg"></param>
public void SendMsg(string msg)
{

clientSkt.Send(Encoding.UTF8.GetBytes(msg));
}



}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Collections.Generic;

namespace Unity聊天室服务端
{

class Program
{
public static List<Client> accptClientList = new List<Client>();
/// <summary>
/// 将msg广播给所有现在仍然连接的客户端
/// </summary>
/// <param name="msg"></param>
public static void BroadcastMsg(string msg)
{


/*foreach是只读模式,在里面不能删除自己,因为一旦删除,就会重新排序
* 比如原来的索引0被删除了,下一次foreach的索引0就会变成原来的1
* 1就会变成2,所以会报“集合已修改;可能无法执行枚举操作”的错误
*/

//foreach(Client clt in accptClientList)
//{
// if(clt.Connected)
// {
// clt.SendMsg(msg);
// Console.WriteLine("发送消息成功");
// }
// else
// {
// accptClientList.Remove(clt);
// }
//}

for (int i = 0; i < accptClientList.Count; i++)
{
accptClientList[i].SendMsg(msg);
}
}

static void Main(string[] args)
{
Socket serveSkt = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

//绑定ip和端口
serveSkt.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.4"), 10086));

//开始监听消息
serveSkt.Listen(10);
Console.WriteLine("服务端正在运行");

while (true)
{
Socket client = serveSkt.Accept();
accptClientList.Add(new Client(client));
}

}
}
}

Unity 部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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 ChatManage : MonoBehaviour {

private Socket client;
private Thread t;
private byte[] receiveMsg;
private byte[] sendMsg;
private string receiveSting;

public InputField inputField;
public Button sendBtn;
public Text msgText;


private void Awake()
{

}
// Use this for initialization
void Start () {

sendMsg = new byte[1024];
receiveMsg = new byte[1024];
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect(new IPEndPoint(IPAddress.Parse("192.168.1.4"), 10086));


t = new Thread(ReceiveMsg);
t.Start();

/*
* receive不要写在主线程里面,不然服务端那边如果一直不传递消息过来的话
* 主线程就会一直堵塞
*/
}

// Update is called once per frame
void Update () {
Debug.Log("收到消息为"+receiveSting);
if (receiveSting != "")
{
msgText.text += ("\n" + receiveSting);
receiveSting = "";
}
}

void ReceiveMsg()
{
while (true)
{
if (client.Connected)
{
int lenth = client.Receive(receiveMsg);
receiveSting = Encoding.UTF8.GetString(receiveMsg, 0, lenth);
}
else break;
}
}

public void OnSendBtn()
{
if(inputField.text!="")
{
sendMsg = Encoding.UTF8.GetBytes(inputField.text);
client.Send(sendMsg);
inputField.text = "";
}

}
private void OnDestroy()
{
//t.Abort();
client.Shutdown(SocketShutdown.Both);
client.Close();
}
}