前言
本文展示的是 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就好了。
初始化运行展示
服务端开始运行:
运行第一个客户端:
此时服务器状态:
同理运行第二个客户端后,服务器状态:
指令功能展示
①username:xxxxx // 此命令用于用户名注册
在第一个客户端输入:username:aaaaa
在第二个客户端输入:username:bbbbb
②group:xxxxxxx // 此命令用于消息广播,即所有用户收的到该消息
在第一个客户端输入:group:hello java! i'm cllient1.
③private:用户名-xxxxxx // 此命令用于向用户名用户发送xxxxxx内容
在第一个客户端输入:private:bbbbb-i'm cllient1.
则客户端2(bbbbb)会收到消息:
④ -exit // 此命令仅用于客户端
在第二个客户端输入:-exit
总结
本程序实现的基本功能大概就这样,想要实现更复杂的功能,只需要从发送的消息的格式上入手即可。本程序的指令格式都是 指令:(对象-)内容。看代码思路应该还是比较轻松吧~