JAVASE02-Unit011: TCP通信(小程序)

    TCP通信(小程序)    

server端:

package chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
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;

/**
 * 聊天室服务端
 * @author adminitartor
 *
 */
public class Server {
    /*
     * 运行在服务端的ServerSocket,主要作用:
     * 1:向操作系统申请服务端口,客户端就是通过
     *   这个端口与服务端程序建立连接的
     * 2:监听服务端口,一旦客户端连接了,就会创建
     *   一个Socket以便与该客户端交互  
     */
    private ServerSocket server;
    /*
     * 该集合存放所有客户端的输出流,以便于广播
     * 消息给所有客户端
     */
    private List<PrintWriter> allOut;
    
    /**
     * 构造方法,用来初始化服务端
     * @throws Exception
     */
    public Server() throws Exception{
        /*
         * 初始化,并申请服务端口,若该端口被
         * 其他应用程序占用,这里会抛出异常
         */
        server = new ServerSocket(8088);
        
        allOut = new ArrayList<PrintWriter>();
        
    }
    /**
     * 广播消息
     * @param message
     */
    public void sendMessage(String message){
        synchronized (allOut) {
            for(PrintWriter out : allOut){
                out.println(message);
            }
        }
    }
    
    public void start(){
        try {
            /*
             * ServerSocket提供方法:
             * 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) {
        try {
            Server server = new Server();
            server.start();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("服务端运行失败!");
        }
    }
    
    /**
     * 该线程的任务是用来与指定的客户端进行
     * 交互
     * @author adminitartor
     *
     */
    private class ClientHandler 
                    implements Runnable{
        //当前线程通过该Socket与客户端交互
        private Socket socket;
        
        //该客户端的IP地址信息
        private String host;
        
        //该客户端的昵称
        private String nickName;
        
        public ClientHandler(Socket socket){
            this.socket = socket;
            /*
             * 通过Socket获取远端计算机的地址
             * 信息
             */
            InetAddress address
                = socket.getInetAddress();
            //获取ip地址信息
            host = address.getHostAddress();
        } 
        
        public void run(){
            PrintWriter pw = null;
            try {
                /*
                 * Socket提供了方法:
                 * InputStream getInputStream()
                 * 该方法可以获取一个输入流,通过该流
                 * 读取到的内容就是远端计算机发送过来的数据
                 */
                InputStream in
                    = socket.getInputStream();
                
                InputStreamReader isr
                    = new InputStreamReader(in,"UTF-8");
                
                BufferedReader br
                    = new BufferedReader(isr);
                
                /*
                 * 首先单独读取一行字符串,该字符串为
                 * 当前客户端的昵称
                 */
                nickName = br.readLine();
                
                
                /*
                 * 通过Socket获取输出流,以便将消息发送
                 * 给客户端
                 */
                pw = new PrintWriter(
                    new OutputStreamWriter(
                        socket.getOutputStream(),
                        "UTF-8"
                    ),true    
                );
                /*
                 * 将当前客户端的输出流存入共享集合
                 */
                synchronized (allOut) {
                    allOut.add(pw);
                }        
                
                //广播当前用户上线
                sendMessage(nickName+"上线了...");
                
                
                
                String message = null;
                /*
                 * 读取客户端发送过来的消息时,当客户端断开连接
                 * 时,由于客户端系统不同,这里readLine方法的
                 * 执行结果也不同:
                 * 当windows的客户端断开后:这里会抛出异常
                 * 当linux的客户端断开后:这里会返回null
                 */
                while((message = br.readLine())!=null){
//                    System.out.println(host+"说:"+message);
//                    //将消息发送给客户端
//                    pw.println(host+"说:"+message);
                    //将消息广播给所有客户端
                    sendMessage(nickName+"说:"+message);
                }
                
            } catch (Exception e) {
                
            } finally{
                /*
                 * 处理客户端断开连接后的操作
                 */
                //将该客户端的输出流从共享集合删除
                synchronized (allOut) {
                    allOut.remove(pw);
                }        
                
                
                sendMessage(nickName+"下线了...");            
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } 
            }
        }
    }
    
    
}
Server.java

client端:

package chat;

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

/**
 * 聊天室客户端
 * @author adminitartor
 *
 */
public class Client {
    /*
     * 封装了TCP通讯的Socket
     * 使用它可以与服务端建立连接,并进行通讯
     * 
     */
    private Socket socket;
    /**
     * 构造方法,用来初始化客户端
     */
    public Client() throws Exception{
        /*
         * 实例化Socket的过程就是连接服务端的
         * 过程。若连接失败,这里会抛出异常
         * 
         * 构造方法的两个参数:
         * 1:服务端计算机的IP地址
         * 2:服务端应用程序的端口
         */
        socket = new Socket(
            "localhost",8088    
        );
    }
    /**
     * 客户端开始工作的方法
     */
    public void start(){
        try {
            Scanner scanner = new Scanner(System.in);
            
            /*
             *  先要求用户输入一个昵称:
             */
            String nickName = null;
            
            while(true){
                System.out.println("请输入您的昵称:");
                nickName = scanner.nextLine().trim();
                if(nickName.length()>0){
                    break;
                }
                System.out.println("请至少输入一个字符");
            }
            
            /*
             * Socket提供了方法:
             * OutputStream getOutputStream()
             * 该方法会获取一个输出流,通过该输出
             * 流写出的数据会发送给远端计算机。
             */
            OutputStream out
                = socket.getOutputStream();
            
            OutputStreamWriter osw
                = new OutputStreamWriter(out,"UTF-8");
            
            PrintWriter pw 
                = new PrintWriter(osw,true);                    
            
            /*
             * 输出流创建完毕后先单独将昵称
             * 发送至服务端
             */
            pw.println(nickName);
            
            /*
             * 将读取服务端消息的线程启动起来
             */
            ServerHandler handler
                = new ServerHandler();
            Thread t = new Thread(handler);
            t.start();
            
            String message = null;
            while(true){
                message = scanner.nextLine();
                pw.println(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        try {
            Client client = new Client();
            client.start();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("客户端运行失败!");
        }
    }
    /**
     * 该线程负责接收服务端发送过来的消息并
     * 输出到客户端的控制台。
     * @author adminitartor
     *
     */
    private class ServerHandler 
                        implements Runnable{
        public void run(){
            try {
                BufferedReader br = new BufferedReader(
                    new InputStreamReader(
                        socket.getInputStream(),"UTF-8"    
                    )
                );
                String message = null;
                while((message = br.readLine())!=null){
                    System.out.println(message);
                }
            } catch (Exception e) {
                
            }
        }
    }
    
}
Client.java
原文地址:https://www.cnblogs.com/tangshengwei/p/6266777.html