java客户端与服务端建立连接 线程 ServerSocket
package chat;

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 Client {
    /*
     * java.net.Scoket 套接字
     * 封装了TCP通讯,使用它可以通过网络连接到服务端并进行数据交换(通讯)
     */
    private Socket socket;
    /*
     * 构造方法
     * 用于初始化客户端
     */
    public Client() throws Exception{
        try {
            /*
             * 实例化Scoket的过程就是与远端计算机建立连接的过程
             * 实际上建立连接是客户端应用程序与服务端应用程序建立的连接
             * 那么这里实例化Scoket需要传入两个参数
             * 1:服务器端计算机的IP地址(用于在网络中找到服务器端电脑)
             * 2:端口号(通过端口号可以找到运行在服务器中的服务端应用程序)
             */
            System.out.println("正在连接服务器。。。");
            socket = new Socket("localhost",8080);
            System.out.println("已建立连接!");
        } catch (Exception e) {
            throw e;
        }
    }
    /*
     * 客户端的启动方法
     */
    public void start(){
        try {
            /*
             * Socket 提供方法:
             * OutputStream getOutputStream
             * 该方法可以获取一个字节输出流,通过该流写出的数据都会发送给远端计算机
             * 对于客户而言,远端就是服务端
             */

            Scanner scan = new Scanner(System.in);
            //客户端输出
            OutputStream out = socket.getOutputStream();
            //转换指定字符集
            OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
            //缓冲 字符输出流
            PrintWriter pw = new PrintWriter(osw,true);

            //启动读取服务端发送过来消息的线程
            ServerHandler handler = new ServerHandler();
            Thread t = new Thread(handler);
            t.start();


            System.out.println("开始聊天");
            String message = null;
            while(true){
                message = scan.nextLine();
                pw.println(message);
//              //读取服务端发送回来的内容
//              message = br.readLine() ;
//              System.out.println(message);
            }

        } catch (Exception e) {
            e.printStackTrace();
            }
    }
    /*
     * 该线程专门用来接收服务端发送过来的消息并输出到控制台
     */
    private class ServerHandler 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();
            }
        }
    }

    public static void main(String[] args) {
        try {
            Client client = new Client();
            client.start();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
package chat;

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.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/*
 * 服务器端
 * 
 */
public class Server {
    /*
     * java.net.ServerSocket; 运行在服务端的ServerScoket主要职责:
     * 1:向OS申请服务端口(客户端就是同过这个端口与服务端建立连接的) 
     * 2:监听服务端口并建立与客户端的连接
     */
    private ServerSocket server;
    //存放所有客户端的输出流,用于广播消息
    private List<PrintWriter> allOut;
    /*
     * 服务端构造方法,用来初始化服务端
     */
    public Server() throws Exception {
        try {
            /*
             * 初始化ServerSocket的同时向系统申请服务器端口, 若该端口已经被其他程序占用则会抛出异常
             */
            server = new ServerSocket(8080);
            allOut = new ArrayList<PrintWriter>();

        } catch (Exception e) {
            // 将来在这里可以记录日志
            // 异常若不应当在这里处理,继续抛出
            throw e;
        }

    }

    /*
     * 服务端开始工作的方法
     */
    public void start() {

        try {
            /*
             * ServerSocket提供方法: Socket accept()
             * 该方法是一个阻塞方法,作用是监听服务端口,等待客户端的连接一旦一个客户端请求连接
             * 那么accept方法会解除阻塞,并返回一个Socket实例,服务器就可以通过这个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();
        }

    }

    private class ClientHandler implements Runnable {
        /*
         * 当前线程就是通过这个Socket与指定客户端交互的
         * 
         */

        private Socket socket;

        //当前客户端的地址信息
        private String host;


        public ClientHandler(Socket socket) {
            this.socket = socket;
            //获取该客户端地址信息(远端计算机地址信息)
            InetAddress address = socket.getInetAddress();
            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);

                // 服务端输出
                OutputStream out = socket.getOutputStream();
                // 转换指定字符集
                OutputStreamWriter osw = new OutputStreamWriter(out, "UTF-8");
                // 缓冲 字符输出流
                pw = new PrintWriter(osw, true);


                //将该客户端的输出流存入共享集合
                synchronized(allOut){//锁集合 保证多个线程不能同时调用
                    allOut.add(pw);
                }
                //广播当前客户端上线
                sendMessage(host+"上线了");

                String message = null;
                while ((message = br.readLine()) != null) {
                    Thread t = Thread.currentThread();
                    System.out.println("客户" +t.getName()+":"+ message);
//                  // 发送回给客户端
//                  pw.println("客户端说:" + message);

                    //遍历集合,发送给所有客户端
                    sendMessage(host+":"+message);

                }

            } catch (Exception e) {
                //e.printStackTrace();
            }finally{


                //处理客户端断开连接后的操作

                //将该客户端的输出流从共享集合中删除
                synchronized(allOut){
                    allOut.remove(pw);

                }
                sendMessage(host+"下线了");

                try{
                    /*
                     * 网络通讯完毕后关闭socket
                     */
                socket.close();
                }catch(Exception e){
                }

            }

        }
    /*
     * 将消息广播给所有客户端
     */
        private void sendMessage(String message){
            synchronized(allOut){
                for(PrintWriter o : allOut){
                    o.println(message);
                }
            }
        }
    }


    public static void main(String[] args) {
        try {
            Server server = new Server();
            server.start();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
阅读更多
文章标签: java
个人分类: 学习java
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

java客户端与服务端建立连接 线程 ServerSocket

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭