Java Socket编程 多线程server和client通信demo

server代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class TCPServer {
    public static Map<String, Socket> socketMap = new HashMap<String, Socket>();

    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(10000);// 创建服务器socket,监听10000端口

        // 开启信息发送的线程
        sendMsgThread();
        // 循环进行与客户端的连接
        while (true) {
            Socket socket = server.accept();// 阻塞,等待客户端的连接
            serverThread(socket);// 新建通信线程
        }
    }

    /**
     * 
     * @Title: serverThread
     * @Desc: 多线程 接收客户端信息
     *
     * @param socket
     *            参数
     *
     */
    public static void serverThread(Socket socket) {
        // 新线程
        new Thread(new Runnable() {
            public void run() {
                BufferedReader in = null;
                PrintWriter out = null;
                try {
                    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    String msg = in.readLine();// 读取客户发来的信息
                    socketMap.put(msg.split(" ")[1], socket);
                    while (true) {
                        if ("bye".equals(msg.split(":")[1].trim())) {// 若客户端发来bye,则跳出循环,即关闭当前线程
                            socketMap.remove(socket);//将socket从map中移除
                            break;
                        }
                        System.out.println(msg);// 打印客户端发来的信息
                        msg = in.readLine();// 读取客户发来的信息
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {// 关闭io
                    in.lines();
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }
        }).start();// 开启线程,将自动运行run方法
    }

    /**
     * 
     * @Title: sendMsgThread
     * @Desc: 发送信息给客户端
     *
     */
    public static void sendMsgThread() {
        new Thread(new Runnable() {
            PrintWriter out = null;
            BufferedReader toClient = null;

            public void run() {
                try {
                    while (true) {
                        System.out.println("say to who?:");
                        Scanner s = new Scanner(System.in);//输入要发送的客户端的name
                        String name = s.nextLine();
                        Socket socket = socketMap.get(name);//从map中获取name对应的socket
                        if (socket == null) {
                            System.out.println("this client not exist");
                            continue;
                        }
                        out = new PrintWriter(socket.getOutputStream());
                        System.out.println("say what?:");
                        toClient = new BufferedReader(new InputStreamReader(System.in));
                        String send = toClient.readLine();

                        out.println("server " + Thread.currentThread().getId() + " say: " + send);// 将信息发送给客户端
                        out.flush();// 刷新
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    out.close();
                    try {
                        toClient.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }
        }).start();
    }
}

client代码

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

public class TCPClient {
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket("localhost", 10000);// 创建socket,连接localhost(127.0.0.1)的10000端口
        System.out.println("enter your name:");
        Scanner s = new Scanner(System.in);// 控制台输入name
        String name = s.nextLine();// 读取
        System.out.println("say to server:");

        PrintWriter out = new PrintWriter(socket.getOutputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        readThread(socket);
        while (true) {
            String msg = reader.readLine();// 读取控制台输入信息
            out.println("=========>>>client " + name + " say: " + msg);// 发送信息到服务器
            if ("bye".equals(msg)) {
                break;
            }
            out.flush();
        }
        reader.close();
        out.close();
        socket.close();
    }

    /**
     * 
    * @Title: readThread
    * @Desc: 新开线程读取服务器发来的信息
    *
    *  @param socket 参数
    *
     */
    public static void readThread(Socket socket) {
        new Thread(new Runnable() {
            public void run() {
                BufferedReader in = null;
                try {
                    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    while (true) {
                        String str = in.readLine();
                        System.out.println(str);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

    }
}

效果图:
server部分,由于控制台打印按顺序的,看着有点乱,接收到的消息和发送的消息是独立的
这里写图片描述
客户端1,xiaoming
这里写图片描述
客户端2,xiaohong
这里写图片描述

思路,主要把读和写用不同的线程分开弄,要不然读写容易冲突,会阻塞,客户端和服务器都如此
客户端的读取用了多个线程,每个对应一个客户端,写则统一在一个线程里处理,通过map获取对应的socket
基本实现多个客户端和服务器的通信

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值