Simple chat room app implementation: Unity+C# client, Java server

Unity+C# client

The UI interface is typesetting according to personal preferences

                        Figure 1 Enter interface Figure 2 Chat interface

The C# script code is as follows:

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);
        }
        
    }

}

Hang the script on the Camera, bind the corresponding components and buttons

 

 

 

Java server side

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();
        }
    }

}

application test

This test is a local test, simulating a multi-client environment

Start the server first

Then double-open Unity and enter two users

The server-side interface is as follows:

 The client chat interface is as follows:

 

Test passed, can run normally

Package the Java server-side code into a jar package and send it to the server to run

Change the target ip address in the C# code to the server ip, and the Unity client will package the apk file and send it to each mobile phone for installation and operation.

Guess you like

Origin blog.csdn.net/BYZY1314/article/details/127721485