服务器转发客户端消息

服务器端:

package com.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
 
/**
 * 聊天室服务端
 * java.net.ServerSocket
 * ServerSocket是运行在服务端的,其作用是向
 * 系统申请服务端端口,以便监听该端口,等待客户端
 * 的连接。一旦一个客户端连接,就会创建一个Socket
 * 与该客户端进行通信。
 * @author Administrator
 *
 */
public class Server {
    //运行在服务端的ServerSocket
    private ServerSocket server;
     
    //存放所有客户端输出流的集合,用于广播消息
    private List<PrintWriter> allOut;
    /**
     * 构造方法,用来初始化服务端
     */
    public Server(){
        try {
            allOut = new ArrayList<PrintWriter>();
            /*
             * 初始化ServerSocket的同时需要指定服务端口
             * 该端口不能与当前系统使用TCP协议的其他程序
             * 申请的端口冲突,否则会抛出端口被占用的异常
             */
            server = new ServerSocket(8088);
             
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
     
    private synchronized void addOut(PrintWriter pw){
        allOut.add(pw);
    }
    private synchronized void removeOut(PrintWriter pw){
        allOut.remove(pw);
    }
    private synchronized void sendMessageToAllClient(String m){
        for(PrintWriter pw : allOut){
            pw.println(m);
        }
    }
     
     
    /**
     * 服务端开始工作的方法
     */
    public void start(){
        try {
            /*
             * Socket accept()
             * ServerSocket提供的该方法用来监听打开的
             * 服务端口(8088),该方法是一个阻塞方法,直到
             * 一个客户端尝试连接才会解除阻塞,并创建一个
             * Socket与刚连接的客户端进行通讯。
             * 
             * accept方法每次调用都会等待一个客户端连接,
             * 所以若希望服务端能接受若干客户端的连接,就
             * 需要多次调用该方法,来分别获取对应这些客户
             * 端的Socket与他们通讯。
             * 
             */
            while(true){
                System.out.println("等待客户端连接...");
                Socket socket = server.accept();
                System.out.println("一个客户端连接了!");
                /*
                 * 当一个客户端连接后,起动一个线程,来负责
                 * 与该客户端交互。
                 */
                ClientHandler handler = new ClientHandler(socket);
                Thread t = new Thread(handler);
                t.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
     
    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }
    /**
     * 该线程用来与一个指定的客户端进行交互。
     * 每当一个客户端连接服务端后,都会起动
     * 当前线程来负责与之交互工作。
     * @author Administrator
     *
     */
    private class ClientHandler implements Runnable{
        //当前线程交互的客户端的Socket
        private Socket socket;
         
        //客户端的地址信息
        private String host;
         
        public ClientHandler(Socket socket){
            this.socket = socket;
            //通过socket可以得知远端计算机信息
            InetAddress address = socket.getInetAddress();
            //获取远程计算机IP
            host = address.getHostAddress();
             
        }
         
        public void run() {
            PrintWriter pw = null;
            try {       
                /*
                 * 通过客户端的Socket获取输出流,以便将
                 * 消息发送给客户端
                 */
                OutputStream out = socket.getOutputStream();
                OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
                pw = new PrintWriter(osw,true);
                //共享该客户端的输出流
                addOut(pw);
                 
                //广播该用户上线
                sendMessageToAllClient(host+"上线了");
                 
                /*
                 * InputStream getInputStream()
                 * Socket提供的该方法用来获取输入流,读取
                 * 远端计算机发送过来的数据
                 */
                InputStream in = socket.getInputStream();
                 
                InputStreamReader isr = new InputStreamReader(in,"UTF-8");
                 
                BufferedReader br = new BufferedReader(isr);
                 
                String message = null;
                /*
                 * 当我们使用BufferedReader读取来自远端计算机
                 * 发送过来的内容时,由于远端计算机的操作系统
                 * 不同,当他们断开连接时,这里readLine方法
                 * 的结果也不同:
                 * 当远端计算机操作系统是windows时,若断开
                 * 连接,这里的readLine方法直接会抛出异常。
                 * 当远端计算机操作系统是linux时,若断开连
                 * 接,这里的readLine方法返回null。 
                 */
                while((message = br.readLine())!=null){
                    sendMessageToAllClient(host+"说:"+message);
                }       
                 
            } catch (Exception e) {
                 e.printStackTrace();
            } finally{
                /*
                 * 当该客户端与服务端断开连接时,应当将该客
                 * 户端的输出流从共享集合删除。
                 */
                removeOut(pw);
                 
                //广播该用户下线
                sendMessageToAllClient(host+"下线了");
                 
                /*
                 * 无论是linux的客户端,还是windows的
                 * 客户端,当与服务端断开连接后,都应当
                 * 将与该客户端交互的Socket关闭,来释放
                 * 底层资源。
                 */
                if(socket != null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
             
        }
         
    }
     
}

客户端

package com.socket;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Client1 {
	//用来与服务端通信的Socket
    private Socket socket;
     
    /**
     * 构造方法,用来初始化客户端
     * 构造方法常用来初始化对象属性等操作。
     */
    public Client1(){
        try {
            /*
             * 初始化Socket时需要传入两个参数
             * 1:服务端的IP地址
             * 2:服务端的端口号
             * 
             * 首先要清楚:
             * 通讯是客户端计算机上的一个客户端应用程序
             * 与服务端计算机(俗称服务器)上的一个服务端
             * 应用程序之间的通讯。
             * 
             * IP地址的作用是让我们通过网络可以找到服务器
             * 而端口可以让我们找到运行在服务器上的服务端
             * 应用程序。
             * 
             * 创建Socket实例的过程就是与服务端连接的
             * 过程, 若可以成功与服务器连接上,则会创建
             * Socket实例,否则构造方法会抛出异常。
             */
            System.out.println("正在尝试连接服务端...");
            socket = new Socket("localhost",8088);
            System.out.println("与服务端连接成功!");
             
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 客户端开始工作的方法
     */
    public void start(){
        try {
            /*
             * 当客户端启动后,就启动接收服务端发送过来
             * 消息的线程
             */
            GetServerMessageHandler handler
                = new GetServerMessageHandler();
            Thread t = new Thread(handler);
            t.start();
             
            /*
             * 创建一个Scanner用来获取用户输入
             */
            Scanner scanner = new Scanner(System.in);
             
            /*
             * OutputStream getOutputStream()
             * Socket提供了该方法,用来获取输出流来向
             * 服务端发送数据。
             */
            OutputStream out = socket.getOutputStream();
             
            OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
             
            PrintWriter pw = new PrintWriter(osw,true);
             
            while(true){
                String message = scanner.nextLine();
                pw.println(message);
            }
             
             
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
     
    public static void main(String[] args) {
        Client1 client = new Client1();
        client.start();
    }
    /**
     * 由于接收服务端发送过来的消息,与我们给服务端
     * 发送消息没有必然关系,所以两者应当在两个不同
     * 的线程上完成,各做各的,互不干涉。
     * @author Administrator
     *
     */
    private class GetServerMessageHandler implements Runnable{
        public void run() {
            try {
                /*
                 * 该线程的职责就是读取服务端发送过来的
                 * 每一条消息,并输出到控制台。
                 */
                InputStream in = socket.getInputStream();
                InputStreamReader isr
                    = new InputStreamReader(in,"UTF-8");
                BufferedReader br
                    = new BufferedReader(isr);
                 
                String message = null;
                while((message=br.readLine())!=null){
                    System.out.println(message);
                }
                 
                 
            } catch (Exception e) {
                e.printStackTrace();
            }
             
        }
         
    }
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值