Java简单聊天室Socket服务器客户程序

概述

java.net.Socket 代表两台机器之间网络连接的对象

客户端必须要认识服务器,服务器必须要认识所有的客户端。

  • 如何建立客户端与服务器之间的初始连接
  • 如何传送信息到服务器
  • 如何接收来自服务器的信息

建立连接

要创建Socket连接,必须知道服务器在哪里以及用哪个端口来收发数据,也就是IP地址和端口号

try {
    Socket socket = new Socket("192.168.20.135", 5000);
} catch (UnknownHostException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

常用端口

  • 80 # HTTP网页服务器,HTTPS使用443端口,FTP使用20端口
  • 110 # POP3邮件服务器
  • 25 # SMTP邮局交换服务器
  • 23 # Telnet服务器

0~1023端口保留给已知的特定服务使用,可以从1024~65535之间挑选。

数据读写

BufferedReader

使用 BufferedReader 从 Socket 上读取数据

Socket socket = new Socket("192.168.20.135", 5000);
InputStreamReader stream = new InputStreamReader(socket.getInputStream()); //从 Socket 上取得输入串流
BufferedReader reader = new BufferedReader(stream);
String msg = reader.readLine();
reader.close();

PrintWriter

用 PrintWriter 写数据到 Socket 上

Socket socket = new Socket("192.168.20.135", 5000);
PrintWriter writer = new PrintWriter(socket.getOutputStream()); //连接 Socket 和 String 流
writer.println("message to send"); //带换行
writer.print("another message");
writer.close();

Socket Server

一对Socket,一个用于等待用户请求的ServerSocket,一个用于与用户通信的Socket

ServerSocket

try {
    ServerSocket serverSocket = new ServerSocket(4242);
    while(true){ //服务器进入无穷循环等待客户端的请求
        Socket socket = serverSocket.accept(); //此方法会停下来等待要求到达之后再继续
        PrintWriter writer = new PrintWriter(socket.getOutputStream());
        writer.println("Welcome...");
        writer.close();
    }
} catch (IOException e) {
    e.printStackTrace();
}

工作方式

1 服务器应用程序对特定端口创建出ServerSocket

ServerSocket serverSocket = new ServerSocket(4242);

这会让服务器应用程序开始监听来自 4242 端口的客户端请求

2 客户端对服务器应用程序建立Socket连接

Socket socket = new Socket("192.168.20.135", 9000);

客户端根据服务器的IP地址和端口号建立连接

3 服务器创建出与客户端通信的新的Socket

Socket socket = serverSocket.accept();

accept() 方法会在等待用户的Socket连接时闲置着,当用户连上来时,此方法会返回一个不同端口上的新的Socket以便与客户端通信。如此ServerSocket可以空出来等待其他的用户。

取得所有连线

List<PrintWriter> clientOutputStreams = new ArrayList<>();  //定义客户端输出流列表
try {
    ServerSocket serverSocket = new ServerSocket(9000); //监听连接到9000端口的所有客户端
    while(true){
        Socket clientSocket = serverSocket.accept();
        PrintWriter writer = new PrintWriter(clientSocket.getOutputStream()); //取得客户端输出流
        clientOutputStreams.add(writer); //添加到输出流列表
        //启动监听客户端输入流线程
        Thread readClientMsg = new Thread(new ClientHandler(clientSocket));
		readClientMsg.start();
    }
} catch (IOException e) {
    e.printStackTrace();
}

群发消息

public void sendToAll(String msg){
    Iterator<PrintWriter> itClient = clientOutputStreams.iterator(); //利用迭代器进行遍历
    while(itClient.hasNext()){
        PrintWriter writer = itClient.next();
        writer.println(msg);
        writer.flush();
    }
}

取得客户端消息

利用多线程循环监听客户端发来的消息,如果获取到消息就发送给所有用户

线程在取得客户端连接时就启动

Socket clientSocket = serverSocket.accept();
Thread readClientMsg = new Thread(new ClientHandler(clientSocket));
readClientMsg.start();
class ClientHandler implements Runnable{
    BufferedReader reader;
    Socket socket;

    public ClientHandler(Socket clientSocket){
        //绑定客户端并取得输入流
        this.socket = clientSocket;
        try {
            InputStreamReader is = new InputStreamReader(socket.getInputStream());
            reader = new BufferedReader(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        String msg;
        //循环监听输入流,取到消息后发送给所有客户端
        try {
            while((msg = reader.readLine()) != null){
                sendToAll(msg);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }        
}

Socket Client

发送消息给服务器

Socket socket;
PrintWriter writer;
private void setSocket(){
    try {
        socket = new Socket("192.168.20.135", 4242);
        writer = new PrintWriter(socket.getOutputStream());
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } 
}
private void sendMsg(String msg){
    writer.println(msg);
    writer.flush();
}

接收服务器消息

结合以上发送消息合并代码

BufferedReader reader;
private void setSocket(){
    try {
        socket = new Socket("192.168.20.135", 4242);
        writer = new PrintWriter(socket.getOutputStream()); //定义输出流,通过发送按钮发送消息给服务器
        InputStreamReader streamReader = new InputStreamReader(socket.getInputStream()); //定义输入流
        reader = new BufferedReader(streamReader); //绑定到缓存输入流,利用多线程循环循环查询服务器消息并接收
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } 
}

开启新线程循环接收服务器消息

Thread readMsg = new Thread(new ReadMsg());
readMsg.start();
private class ReadMsg implements Runnable{
    @Override
    public void run() {
        String msg;
        try {
            while((msg = reader.readLine()) != null){
                //获取到服务器信息
                System.out.println(msg);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值