简易聊天室app实现:Unity+C# 客户端,Java 服务器端
Posted 百彦子烨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简易聊天室app实现:Unity+C# 客户端,Java 服务器端相关的知识,希望对你有一定的参考价值。
Unity+C# 客户端
UI界面根据个人喜好排版
图1 进入界面 图2 聊天界面
C#脚本代码如下:
Client_dxc.cs
using UnityEngine;
using System.Net.Sockets;
using System.Text;
using System;
using UnityEngine.UI;
public class Client_dxc : MonoBehaviour
public Text GetText;
public InputField InputText;
public InputField ZhuCeInputText;
public Text chatText;
public ScrollRect scrollRect;
public GameObject DengLuJieMian;
private string SetText;
private Socket socket;
private byte[] buffer = new byte[1024];
void Start()
//AddressFamily 寻址类型 SocketType 套接字类型 ProtocolType 协议类型
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//连接服务器
socket.Connect("127.0.0.1", 9999);
Debug.Log("连接成功!");
//开始接收信息
readServer();
void Update()
huoqu();
//接收信息
void readServer()
//Socket异步接收数据
//buffer存储接收到的数据,offset从零开始计数,size要接收的字节数,SocketFlags 值的按位组合
//ReceiveCallback一个用户定义的对象,其中包含接收操作的相关信息。当操作完成时,此对象会被传递给EndReceive(IAsyncResult)委托
socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);
void ReceiveCallback(IAsyncResult iar)
int len = socket.EndReceive(iar);
if (len == 0)
return;
string str = Encoding.UTF8.GetString(buffer, 0, len);
SetText = str;
//循环接收数据
readServer();
//发送信息
void sendServer(string msg)
//将字符串转换为UTF-8编码的字节数组
var outputBuffer = Encoding.UTF8.GetBytes(msg);
//将数据异步发送到连接的 Socket
//BoutputBuffer包含要发送的数据,SocketFlags 值的按位组合,callback:AsyncCallback 委托,state:Object 包含此请求的状态信息的对象
socket.BeginSend(outputBuffer, 0, outputBuffer.Length, SocketFlags.None, null, null);
//获取信息输出到信息面板上
public void huoqu()
if (SetText != "")
string addText = "\\n " + SetText;
//将获取的信息添加到信息面板中
chatText.text += addText;
SetText = "";
//强制画布更新内容
Canvas.ForceUpdateCanvases();
//垂直滚动位置,以 0 到 1 之间的值表示,0 表示位于底部
scrollRect.verticalNormalizedPosition = 0f;
Canvas.ForceUpdateCanvases();
//绑定“发送”按钮(群发消息)
public void qunInput()
if (InputText.text != "")
string msg = "Mass:" + InputText.text + "\\r\\n";
sendServer(msg);
InputText.text = "";
//绑定“进入”按钮(进入群聊注册用户名)
public void ZhuCe()
if (ZhuCeInputText.text != "")
string msg = "userName:" + ZhuCeInputText.text + "\\r\\n";
sendServer(msg);
DengLuJieMian.SetActive(false);
将脚本挂在Camera上,绑定对应组件及按钮
Java 服务器端
Main.java
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Main
public static void main(String[] args)
try
//创建ServerSocket对象,监听9999端口
ServerSocket serversocket = new ServerSocket(9999);
System.out.println("----------服务器启动----------");
System.out.println("开始监听:");
//创建一个循环,使主线程持续监听
while (true)
//做一个阻塞,监听客户端
Socket socket = serversocket.accept();
//创建一个新的线程,将客户端socket传入
Server server = new Server(socket);
//启动线程
server.start();
catch (IOException e)
throw new RuntimeException(e);
Server.java
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Server extends Thread
//创建一个Map集合
private static Map<String,Socket> map = new ConcurrentHashMap<>();
//创建Socket对象
private Socket socket;
public Server(Socket socket)
this.socket = socket;
//重写run方法
public void run()
try
//获取客户端的输入流
Scanner scanner=new Scanner(socket.getInputStream());
String msg=null;
//写一个循环来持续处理获取到的信息
while (true)
//判断是否接收到了字符串
if(scanner.hasNextLine())
//获取信息
msg=scanner.nextLine();
//处理客户端输入的字符串
Pattern pattern=Pattern.compile("\\r");
Matcher matcher=pattern.matcher(msg);
msg=matcher.replaceAll("");
//判断字符串是不是以userName:为前缀的
if(msg.startsWith("userName:"))
//将字符串从:拆分开,后半部分存入userName中
String userName=msg.split(":")[1];
//注册该用户
userEnroll(userName,socket);
//将Map集合转换为Set集合
Set<Map.Entry<String,Socket>> set=map.entrySet();
//遍历集合,向所有用户发送消息
for(Map.Entry<String,Socket> entry:set)
//取得客户端的Socket对象
Socket client=entry.getValue();
//取得client客户端的输出流
PrintStream printstream=new PrintStream(client.getOutputStream());
//向客户端发送信息
printstream.println(userName + "加入了群聊!");
continue;
//判断字符串是不是以Mass:为前缀的
if(msg.startsWith("Mass:"))
//拆分字符串,获取信息内容
String str=msg.split(":")[1];
//发送群聊信息
MassSend(socket,str);
catch (IOException e)
throw new RuntimeException(e);
//注册用户
private void userEnroll(String userName,Socket socket)
//将键值对添加入Map集合中
map.put(userName,socket);
//打印日志
System.out.println("[用户名为"+userName+"][客户端为"+socket+"]上线了!");
System.out.println("积累进入人数为:"+map.size()+"人");
//发送消息
private void MassSend(Socket socket,String msg)
try
//将Map集合转换为Set集合
Set<Map.Entry<String, Socket>> set = map.entrySet();
String SendName = null;
//遍历Set集合找到发起群聊信息的用户
for (Map.Entry<String, Socket> entry : set)
//判断集合中的值是否与发起群聊的用户相同
if (entry.getValue().equals(socket))
//获取键名
SendName = entry.getKey();
break;
//遍历Set集合将群聊信息发给每一个客户端
for (Map.Entry<String, Socket> entry : set)
//取得客户端的Socket对象
Socket client = entry.getValue();
//取得client客户端的输出流
PrintStream printStream = new PrintStream(client.getOutputStream());
//发送消息
printStream.println(SendName + ":" + msg);
catch (IOException e)
e.printStackTrace();
应用测试
本次测试为本机测试,模拟多客户端环境
先启动服务器
然后双开Unity,进入两个用户
服务器端界面如下:
客户端聊天界面如下:
测试通过,可正常运行
将Java服务器端代码打包成jar包,发送到服务器上运行即可
将C#代码中的目标ip地址改为服务器ip,Unity客户端打包apk文件,发送到各个手机端安装运行即可
linux C语言 TCP 多线程 简易聊天室
只有一个客户端的话,接收发送都没什么问题,但是有第二个客户端参与的话,第一个客户端就不能发送了,但是可以接收,仔细看了下,问题应该在 服务器端的recv函数的第一个参数id,如果用进程做,可以复制数据,有2个客户端就有两个id,但是用线程做,线程之间数据共用,第二个客户端来了之后,第一个id就被第二个id覆盖了,这个问题要怎么解决呢?求指教
参考技术A 你accept得到一个新的连接后,再创建线程(把连接socket传给线程),用这个线程专门接收这个连接的数据,就不会有问题了。追问你的意思是 每对话一次,客户端都close,然后再不停的connect吗?
追答和客户端通讯的时候线程就活着,客户端断开了,线程就结束。
没有要客户端主动断掉,但是客户端总有断的时候吧?
如果永远不断,那服务端线程也一直存在。
不是啊,我用线程
以上是关于简易聊天室app实现:Unity+C# 客户端,Java 服务器端的主要内容,如果未能解决你的问题,请参考以下文章