基于TCP协议的双向聊天室

基于TCP通讯实现简单的群聊功能

TCP较于UDP来说,数据安全,但是效率没有UDP高;原因是TCP协议在传输上,会验证数据的完整性,而UDP不会。

  • UDP只是单纯的负责发送信息和内容,不会去care你发送的内容这意味着,并且在传输过程中容易丢包
  • 而TCP在发送的时候会验证数据的完整性,在发送的时候 如果出错了则不会进行发送,正是因为多了这一步操作,所以发送速度较于UDP会相对慢一些

且UDP的发送主要关注两个点:DatagramSocket、DatagramPacket 前者是负责发送数据包,而后者则是将数据倒成包

而TCP的发送是通过IO流的方式进行发送,且当服务启动以后,就不会区分服务器和客户端了

  1. 简单一对一聊天:
    首先服务端调用ServerSocket对象,并且指定客户端端口,同时调用accept方法等待客户端进行连接

    System.out.println("server");
    ServerSocket serverSocket = new ServerSocket(8888);
    while (true){
        new Thread(()->{


            boolean flg = true;
            //接收消息
            DataInputStream dis = null;
            try {
                Socket socket = serverSocket.accept();
                System.out.println("客户端建立连接");
                dis = new DataInputStream(socket.getInputStream());
                DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                while(flg){

                    String msg = dis.readUTF();
                    System.out.println(msg);
                    //返回消息

                    dos.writeUTF(msg);
                    flg = msg.equals("bye")?false:true;
                }

                dos.flush();
                dos.close();
                dis.close();
                socket.close();

同时客户端指定服务端需要访问的端口,并通过IO进行流的输入和输出。

System.out.println("client");

//后期可以动态传入ip实现两个电脑端相互聊天
Socket server = new Socket("localhost",8888);
DataOutputStream dos = new DataOutputStream(server.getOutputStream());
DataInputStream dis = new DataInputStream(server.getInputStream());
Scanner sc = new Scanner(System.in);
System.out.println("请输入要传输的内容");
boolean flg= true;
    while (flg){
    String test = sc.next();
    dos.writeUTF(test);
    System.out.println(dis.readUTF());
    flg = test.equals("bye")?false:true;
}
dos.close();
dis.close();
server.close();
dos.flush();

这样,双向聊天的功能就基本实现了,但是现在的代码,只能实现一问一答,也就是说你发送一条信息,必须等对方回复后你才能继续提问。这样就显得很被动。由此就可以看上面代码的鸡肋
所以 我们还需要在上面的代码上进行扩展,实现群聊以及解除一问一答限制的需求。

这里直接上代码,通过代码进行讲解。

服务端:

package com.test.javaUDPTCPtest.Level2TCP;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;

public class Server{	

	//不使用ArrayList的原因是在聊天过程中可能会对list进行各种操作,所以在这里结合情况,选择使用CopyOnWriteArrayList
    private static CopyOnWriteArrayList<channel> channels = new CopyOnWriteArrayList<>();
    public static void main(String[] args) throws IOException {

	//创建接口
        ServerSocket serverSocket = new ServerSocket(8888);
        //循环接收
        while (true) {
            Socket socket = serverSocket.accept();
           channel ch = new channel(socket);
            channels.add(ch);
            System.out.println("客户端建立连接");
            new Thread(ch).start();
        }
    }
	
	//一个channel代表一个用户
    static class channel implements Runnable{
        private Socket socket;
        private ServerSocket server;
        private DataInputStream dis;
        private DataOutputStream dos;
        private boolean flg = true;
        private String name;

        public channel(Socket socket) {
            this.socket = socket;
            this.name = name;
            try {
            	//输出流
                 dos = new DataOutputStream(socket.getOutputStream());
                 //输入流
                 dis = new DataInputStream(socket.getInputStream());
                 this.name = receive();
            } catch (IOException e) {
            }

        }

        //接收
        public String receive() throws IOException {
            String msg = "";
                msg = dis.readUTF();
            System.out.println("客户端发送:"+msg);
            return msg;
        }
        //发送
        public void send(String msg) throws IOException {
                dos.writeUTF(msg);

        }

        //对信息的发送人进行判断,确保信息只发给除了自己以外的人(后期可做扩张)
        public void sendmy(String msg) throws IOException {
            //约定私聊格式为@xxx:msg
            boolean first = msg.startsWith("@");
            if(true){
                int idx = msg.indexOf(":");
                String targetname = msg.substring(1,idx);
                msg = msg.substring(idx+1);
                for(channel c : channels){
                    if(c.name.equals(targetname)){
                        c.send(this.name+"私聊你说:"+msg);
                    }
                }

            }else{
                for(channel c : channels){
                    if(c==this){
                        continue;
                    }else{
                        c.send(this.name+"对所有人说:"+msg);
                    }
                }
            }

        }

        @Override
        public void run() {
            while(flg){
                String msg = "";
                try {
                    msg = receive();
                    sendmy(msg);
                } catch (IOException e) {
                }
                if(msg.equals("end")){
                        flg = false;
                    try {
                        dos.close();
                        dos.flush();
                        dis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

            }

            }

        }
    }



}

客户端:

package com.test.javaUDPTCPtest.Level2TCP;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws IOException{
        Socket server = new Socket("localhost",8888);
        System.out.println("请输入用户名");
        String name = new Scanner(System.in).next();
        new Thread(new Send(server,name)).start();
        new Thread(new Receive(server)).start();

    }

}


客户端接收方法:

package com.test.javaUDPTCPtest.Level2TCP;

import java.io.*;
import java.net.Socket;

public class Receive implements Runnable{
    private Socket socket;
    private DataInputStream dis;
    private boolean flg= true;

    public Receive(Socket socket) throws IOException {
        this.socket = socket;
        dis = new DataInputStream(socket.getInputStream());
    }

    public void receive() throws IOException {
        String msg = dis.readUTF();
        System.out.println(msg);
        flg = msg.equals("end")?false:true;
    }
    @Override
    public void run() {
        while(flg){
            try {
                receive();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端发送方法:

package com.test.javaUDPTCPtest.Level2TCP;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class Send implements Runnable{
    private BufferedReader bf;
    private Socket socket;
    private DataOutputStream dos;
    private boolean flg= true;
    private String name;

    public Send(Socket socket,String name) throws IOException {
        System.out.println("请输入内容");
        this.socket = socket;
        this.name = name;
        bf = new BufferedReader(new InputStreamReader(System.in));
        dos = new DataOutputStream(socket.getOutputStream());
        //发送用户名
        send(name);
    }

    public void send(String msg) throws IOException {
            dos.writeUTF(msg);
            flg = msg.equals("end")?false:true;
    }

    @Override
    public void run() {
        while(flg){
            try {
                String msg = bf.readLine();
                send(msg);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

这样,一个乞丐版聊天室就做好了 这里并没有引进web场景和模块 而是通过console进行模拟交流,但是正常网页的嵌套客服聊天功能是可以在此基础上进行修改的 方法也比较简单在这里不多做赘述,有兴趣的朋友可以自己尝试一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值