个人学习笔记平台,欢迎大家交流

红叶~

Be humble, communicate clearly, and respect others.

java TCP中的常用类

获取本地ip

 initComponents();//在此处后面添加:

  try {

​      InetAddress addr = InetAddress.getLocalHost();

​      txtHostName.setText( addr.getHostAddress());
​    } catch (UnknownHostException e) {

​      e.printStackTrace();

​    }

TCP 中常用的类和方法

Socket类

Socket(InetAddress address,int port)

创建一个流套接字并

Socket(String host,int port)

创建一个流套接字并将其连接到指定主机上的指定端口号。

Socket(InetAddress address,int port,InetAddress localAddr,int localPort)

创建一个套接字并将其连接到指定远程地址上的指定远程端口

Socket(String host,int port,InetAddress localAddr,int localPort)

创建一个套接字并将其连接到指定远程主机上的指定远程端口。

Close()

关闭套接字

Connect(SocketAddress endpoint)

将此套接字连接到服务器。

SocketAddress server = new InetSocketAddress(“localhost”,5000);

Socket clientSocket = new Socket();

clientSocket.connect(server);

bind(SocketAddress serverAddr)

SocketAddress serverAddr = new InetSocketAddress(InetAddress.getByName(hostName),hostPort);
ServerSocket listenSocket = new ServerSocker(); // 创建侦听套接字
listenSocket.bind(serverAddr); // b

Connect(SocketAddress endpoint,int timeout) 设置一个超时值

getInetAddress() 返回套接字的地址

getInputStream() 返回套接字的输入流

getLocalPort() 返回此套接字绑定的本地端口

getOutputStream() 返回套接字的输出流

getPort() 套接字连接的远程端口

ServerSocket类

ServerSocket(int port)

创建绑定到特定端口的服务器套接字

accept()

侦听并接受到此套接字的连接

getInetAddress()

返回此服务器套接字的本地地址

image-20210913203452860

注意

一个socket套接字通信分别对应这连接这个socket的两端服务器和客户端的输入输出流,这是一对的,因为socket构建了一个通信的流的通道,当存在多个用户连接时候,又会是一个新的socket---->从而又存在另一对通信流的输入输出流。

TCP实现多个用户之间相互通信(即时聊天)

前面实现了服务器与多个客户端之间的通信,我们真正的目的是要实现多个客户端之间的通信

方案

客户端的数据包通过服务器中转,发送到另一个客户端

实现步骤

1、对象序列化(对象需要在网络上传输)

数据包(发送消息者,接收消息者,消息类型(登录、发送),发送的消息内容)

2.定义消息类型

消息类型:登录、发送

3、服务器

启动服务器、用动态序列容器Vector保存在服务器中保存的所有线程的任务对象、每个对象创建一个线程来处理

4、客户端

启动客户端、发送登录信息、接收消息的线程、处理消息发送的线程

代码实现

对象实例化

public class Message implements Serializable {
 
    private String from; //发送者
    private String to;   //接收者
    private int type; //消息类型
    private String info;//消息包
 
    public Message() {
    }
 
    public Message(String from, String to, int type, String info) {
        this.from = from;
        this.to = to;
        this.type = type;
        this.info = info;
    }
 
    public String getFrom() {
        return from;
    }
 
    public void setFrom(String from) {
        this.from = from;
    }
 
    public String getTo() {
        return to;
    }
 
    public void setTo(String to) {
        this.to = to;
    }
 
    public int getType() {
        return type;
    }
 
    public void setType(int type) {
        this.type = type;
    }
 
    public String getInfo() {
        return info;
    }
 
    public void setInfo(String info) {
        this.info = info;
    }
}

消息类型

public class MessageType {
 
    public static final int TYPE_LOGIN = 0x1; //登录消息类型
    public static final int TYPE_SEND = 0x2;  //发送消息的类型
}

服务器

public class Server {
    public static void main(String[] args) {
        //保存客户端处理的线程
        Vector<UserThread> vector = new Vector <>();
        //固定大小的线程池,用来处理不同客户端
        ExecutorService es = Executors.newFixedThreadPool(5);
        //创建服务器端的Socket
        try {
            ServerSocket server = new ServerSocket(8888);
            System.out.println("服务器以启动,正在等待连接...");
            while(true){
                //接受客户端的Socket,若没有,阻塞在这
                Socket socket = server.accept();
                //每来一个客户端,创建一个线程处理它
                UserThread user = new UserThread(socket,vector);
                es.execute(user);  //开启线程
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
/**
 * 客户端处理线程:
 */
class UserThread implements Runnable{
    private String name; //客户端的用户名称,唯一
    private Socket socket;
    private Vector<UserThread> vector;   //客户端处理线程的集合
    private ObjectInputStream oIn;    //输入流
    private ObjectOutputStream oOut;  //输出流
    private boolean flag = true;  //标记
 
    public UserThread(Socket socket, Vector<UserThread> vector) {
        this.socket = socket;
        this.vector = vector;
        vector.add(this);    //把当前线程也加入vector中
    }
 
    @Override
    public void run() {
        try {
            //1、构造输入输出流
            System.out.println("客户端:" + socket.getInetAddress().getHostAddress() + "已连接!");
            oIn = new ObjectInputStream(socket.getInputStream());
            oOut = new ObjectOutputStream((socket.getOutputStream()));
            //2、循环读取
            while(flag){
                //读取消息对象
                Message message = (Message)oIn.readObject();
                //获取消息类型,登录还是发送消息
                int type = message.getType();
                //3、判断
                switch (type){
                    //如果是发送消息
                    case MessageType.TYPE_SEND:
                        String to = message.getTo();//发送给谁
                        UserThread ut;
                        //遍历vector,找到接收信息的客户端
                        int size = vector.size();
                        for (int i = 0; i < size; i++) {
                            ut = vector.get(i);
                            //如果名字相同,且不是自己,就把信息发给它
                            if(to.equals(ut.name) && ut != this){
                                ut.oOut.writeObject(message); //发送消息对象
                            }
                        }
                        break;
                    //如果是登录
                    case MessageType.TYPE_LOGIN:
                        name = message.getFrom();//获取用户名
                        message.setInfo("欢迎您!");//设置登录成功信息
                        oOut.writeObject(message);
                        break;
                }
 
            }
 
 
 
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
 
    }
}

客户端

public class Client {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        //单线程池
        ExecutorService es = Executors.newSingleThreadExecutor();
        try {
            //创建客户端
            Socket socket = new Socket("localhost", 8888);
            System.out.println("服务器连接成功!");
            //构建输出输入流
            ObjectOutputStream oOut = new ObjectOutputStream(socket.getOutputStream());
            ObjectInputStream oIn = new ObjectInputStream(socket.getInputStream());
            //1、客户端登录处理
            //向服务器发送登录信息(名字和消息类型)
            System.out.println("请输入名称:");
            String name = input.nextLine();
            //登录时,只自己的名字和消息类型为登录
            Message message = new Message(name, null, MessageType.TYPE_LOGIN, null);
            //发送给服务器
            oOut.writeObject(message);
            //服务器返回 欢迎信息
            message = (Message) oIn.readObject();
            //打印服务器返回的信息+当前客户端的名字
            System.out.println(message.getInfo() + message.getFrom());
            //2、启动读取消息的线程
            es.execute(new readInfoThread(oIn));  //读取线程完成
 
            //3、发送消息
            //使用主线程来发送消息
            boolean flag = true;
            //循环
            while(flag){
                //创建对象
                message = new Message();
                //发给谁
                System.out.println("To:");
                message.setTo(input.nextLine());
                //谁发的,从自己这发
                message.setFrom(name);
                //类型 发送消息
                message.setType(MessageType.TYPE_SEND);
                //发送的内容
                System.out.println("Info:");
                message.setInfo(input.nextLine());
                /*----到此需要发送的消息 对象 封装完毕----*/
                //发送给服务器
                oOut.writeObject(message);
            }
            
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
 
/**
 * 读取其他客户端发来消息
 */
class readInfoThread implements Runnable {
    private ObjectInputStream oIn; //输入流 用来读操作
    private boolean flag = true; //标记
 
    public readInfoThread(ObjectInputStream oIn) {
        this.oIn = oIn;
    }
 
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
 
    @Override
    public void run() {
 
        try {
            //循环 不断读取消息
            while (flag) {
                //读取信息
                Message message = (Message) oIn.readObject();
                //输出用户名+内容
                System.out.println("[" + message.getFrom() + "]对我说:" + message.getInfo());
            }
            //没有数据就关闭
           if(oIn != null){
               oIn.close();
           }
 
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
 
 
    }
}
开启服务器
posted @ 2022-02-15 23:11  红叶~  阅读(110)  评论(0编辑  收藏  举报