前言

本文展示的是 JAVA的socket通信,实现功能有:用户名注册,消息群发,消息私发,客户端退出。

 

服务端代码

// create file rename :SingleServer.java
package project.java;

import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//服务器端
/**
 * Map<String,Socket>
 * 用户注册:username:yyy
 * 群聊:group:hello
 * 私聊:private:yyy-hhh
 */

class  ExcuteClientServer implements Runnable{
    private Socket client;
    private Map<String,Socket> clientMap;
    public ExcuteClientServer(Socket client, Map<String, Socket> clientMap) {
        super();
        this.client = client;
        this.clientMap = clientMap;
    }

    public void run() {
        try {
            //拿到客户端输入流,读取用户信息
            Scanner scanner = new Scanner(client.getInputStream());
            String string = null;
            while(true){
                if(scanner.hasNext()) {
                    string = scanner.nextLine();
                    Pattern pattern = Pattern.compile("\r\n|\r|\n");
                    Matcher matcher = pattern.matcher(string);
                    string = matcher.replaceAll("");
                    //用户注册
                    if(string.startsWith("user")) {
                        //获取用户名
                        String useName = string.split("\\:")[1];
                        userRegist(useName, client);
                        continue;
                    }
                    //群聊
                    else if(string.startsWith("group")) {
                        String message = string.split("\\:")[1];
                        gropChat(message);
                        continue;
                    }
                    //私聊
                    else if(string.startsWith("private")) {
                        String temp = string.split("\\:")[1];
                        //取得用户名
                        String useName = temp.split("\\-")[0];
                        //取得消息内容
                        String message = temp.split("\\-")[1];
                        privateChat(useName, message);
                        continue;
                    }
                    //用户退出
                    else if(string.contains("-exit")) {
                        //先根据Socket知道用户名
                        String useName = getUseName(client);
                        System.out.println("用户名为"+useName +"的用户下线了!!!");
                        clientMap.remove(useName);
                        continue;
                    }
                }
            }
        }catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    //获取key值(即由端口号找到用户名)
    public String getUseName(Socket socket) {
        String useName = null;
        for(String getKey : clientMap.keySet()) {
            if(clientMap.get(getKey).equals(socket)) {
                useName = getKey;
            }
        }
        return useName;
    }
    //注册实现
    public void userRegist(String useName,Socket client) {
        System.out.println("用户姓名为:" + useName);
        System.out.println("用户socket为:" + client);
        System.out.println("用户名为"+ useName +"的用户上线了!");
        System.out.println("当前用户数为:"+ (clientMap.size()+1) +"人");
        clientMap.put(useName, client);
    }
    //群聊实现
    public void gropChat(String message) {
        Iterator<Entry<String, Socket>> iterable = clientMap.entrySet().iterator();
        for(Map.Entry<String, Socket> stringSocketEntry:clientMap.entrySet()) {
            try {
                Socket socket = stringSocketEntry.getValue();
                PrintStream printStream = new PrintStream(socket.getOutputStream(),true);
                System.out.println("用户说"+message);
                printStream.println(message);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }
    //私聊实现
    public void privateChat(String useName,String message) {
        //根据对应的useName找到对应的Socket
        Socket privateSocket = clientMap.get(useName);
        try {
            PrintStream printStream = new PrintStream(privateSocket.getOutputStream());
            printStream.println("用户名为"+getUseName(client)+"的用户对你说:"+message);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

public class SingleServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(6666);
        //存取用户信息(用户名和Socket)
        Map<String, Socket> map = new HashMap<String, Socket>();
        //线程池,线程大小为20
        ExecutorService executorService =Executors.newFixedThreadPool(20);
        System.out.println("等待客户连接中...");
        try {
            for(int i = 0;i < 20;i ++) {
                Socket socket = serverSocket.accept();
                System.out.println("有新的用户连接:"+socket.getInetAddress()+socket.getPort());
                executorService.execute(new ExcuteClientServer(socket,map));
            }
            executorService.shutdown();
            serverSocket.close();
        } catch (Exception e) {
        }
    }
}

客户端代码

// create file rename :SingelClient1.java
package project.java;

//客户端
//输入、输出流分别为处于一个线程

import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

class OutToServer1 implements Runnable{
    private Socket client;

    public OutToServer1(Socket client) {
        super();
        this.client = client;
    }

    @Override
    public void run() {
        PrintStream printStream;
        try {
            printStream = new PrintStream(client.getOutputStream(),true);
            Scanner scanner = new Scanner(System.in);
            scanner.useDelimiter("\n");
            while(true) {
                System.out.println("请输入:");
                while(scanner.hasNext()) {
                    String string = scanner.nextLine();
                    printStream.println(string);
                    if(string.equals("-exit")) {
                        System.out.println("客户端退出");
                        printStream.close();
                        scanner.close();
                        //client.close();
                        break;
                    }
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

class ReadFromServer1 implements Runnable{
    private Socket client;
    public ReadFromServer1(Socket client) {
        super();
        this.client = client;
    }
    public void run() {
        try {
            Scanner scanner = new Scanner(client.getInputStream());
            scanner.useDelimiter("\n");
            while(scanner.hasNext()) {
                System.out.println("服务器端输入:"+scanner.nextLine());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

public class SingelClient1 {
    public static void main(String[] args) {
        String serverName = "127.0.0.1";
        int port = 6666;
        Socket client;
        try {
            client = new Socket(serverName,port);
            Thread ouThread = new Thread(new OutToServer1(client));
            Thread inThread = new Thread(new ReadFromServer1(client));
            ouThread.start();
            inThread.start();
        } catch (Exception e) {

            e.printStackTrace();
        }
    }
}

上面展示的是客户端1的代码,客户端2只需要将客户端1复制后将声明和引用类的类名中的1改成2就好了。

 

初始化运行展示

服务端开始运行:

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_socket

运行第一个客户端:

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_socket_02

此时服务器状态:

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_客户端_03

同理运行第二个客户端后,服务器状态:

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_java_04

指令功能展示

①username:xxxxx   // 此命令用于用户名注册

在第一个客户端输入:username:aaaaa

在第二个客户端输入:username:bbbbb

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_java_05

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_用户名_06

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_客户端_07

②group:xxxxxxx  // 此命令用于消息广播,即所有用户收的到该消息

在第一个客户端输入:group:hello java! i'm cllient1.

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_socket_08

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_socket_09

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_网络_10

③private:用户名-xxxxxx   // 此命令用于向用户名用户发送xxxxxx内容

在第一个客户端输入:private:bbbbb-i'm cllient1.

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_socket_11

则客户端2(bbbbb)会收到消息:

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_socket_12

④ -exit // 此命令仅用于客户端

在第二个客户端输入:-exit

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_java_13

java SocketChannel 服务端和客户端相互通信 java socket服务端向客户端发消息_客户端_14

 

总结

本程序实现的基本功能大概就这样,想要实现更复杂的功能,只需要从发送的消息的格式上入手即可。本程序的指令格式都是 指令:(对象-)内容。看代码思路应该还是比较轻松吧~