Socket编程
两个核心类:
ServerSocket——基站类
public ServerSocket(int port)//在本机根据指定端口号创建服务器
public Socket accept()//侦听并接收连接到本服务器的客户端连接,
//此方法会一直阻塞,直到有一个客户端成功连接,返回此连接。
Socket——客户端类
public Socket(String host,int port)//根据指定ip和端口号创建套接字并连接到远程服务器端。
public InputStream getInputStream()//返回此套接字的输入流
public OutputStream getOutputStream()//返回此套接字的输出流
单线程聊天室
服务器类:
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class singleThreadServer {
public static void main(String[] args) throws Exception {
//1.建立基站
ServerSocket server = new ServerSocket(6666);
//2.等待客户端连接
System.out.println("等待客户端连接");
Socket socket = server.accept();
//3.建立连接后,进行数据的输入输出
PrintStream printStream = new PrintStream(socket.getOutputStream(),true,"UTF-8");
printStream.println("hello,i am server!");
Scanner scanner = new Scanner(socket.getInputStream());
if (scanner.hasNext()){
System.out.println("客户端发来的信息为:"+scanner.nextLine());
}
//关闭流
printStream.close();
scanner.close();
socket.close();
}
}
客户端类:
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class singleThreadClient {
public static void main(String[] args) throws Exception {
//1.建立连接
Socket socket = new Socket("127.0.0.1",6666);
//2.进行数据的输入输出
Scanner scanner = new Scanner(socket.getInputStream());
if (scanner.hasNext()){
System.out.println("从服务器发来的信息为:"+scanner.nextLine());
}
PrintStream printStream = new PrintStream(socket.getOutputStream(),true,"UTF-8");
printStream.print("hello,i am client!");
//3.关闭流
printStream.close();
scanner.close();
socket.close();
}
}
多线程聊天室
客户端:
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
//读线程
class ReadFromServer implements Runnable{
private Socket client;
public ReadFromServer(Socket client) {
this.client = client;
}
@Override
public void run() {
try {
//获取输入流来取得服务器发来的信息
Scanner in = new Scanner(client.getInputStream());
while (true){
if (client.isClosed()){
System.out.println("客户端已经关闭");
in.close();
break;
}
if(in.hasNext()){
String msgFromServer = in.nextLine();
System.out.println("服务器发来的信息为:"+msgFromServer);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//写线程
class SendMsgToServer implements Runnable{
private Socket client;
public SendMsgToServer(Socket client) {
this.client = client;
}
@Override
public void run() {
try {
PrintStream out = new PrintStream(client.getOutputStream(),true,"UTF-8");
Scanner in = new Scanner(System.in);
while (true){
System.out.println("请输入要向服务器发送的信息..");
String strFromUser = "";
if (in.hasNext()){
strFromUser = in.nextLine();
}
//向服务器发送信息
out.println(strFromUser);
//byebye
if (strFromUser.contains("byebye")){
System.out.println("当前客户端退出聊天室");
out.close();
in.close();
client.close();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class MutilThreadClient {
public static void main(String[] args) throws IOException {
//根据指定ip及端口号建立连接
Socket client = new Socket("127.0.0.1",6666);
//启动读线程和写线程
Thread readThread = new Thread(new ReadFromServer(client));
Thread sendThread = new Thread(new SendMsgToServer(client));
readThread.start();
sendThread.start();
}
}
服务器:
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Set;
public class MutilThreadServer {
private static Map<String,Socket> clientLists = new ConcurrentHashMap<>();
//专门用来处理每个客户端的输入,输出请求
private static class ExecuteClientRequest implements Runnable{
private Socket client;
public ExecuteClientRequest(Socket client) {
this.client = client;
}
@Override
public void run() {
try {
//获取用户输入流,读取用户发来的信息
Scanner in = new Scanner(client.getInputStream());
String strFromClient = "";
while (true){
if (in.hasNext()){
strFromClient = in.nextLine();
}
//windows下消除用户输入自带的\r
Pattern pattern = Pattern.compile("\r");
Matcher matcher = pattern.matcher(strFromClient);
strFromClient = matcher.replaceAll("");
/* 注册:username:xxx
* 群聊:G:群聊内容
* 私聊:P:用户名-私聊内容
* 用户退出:byebye*/
//注册流程
if (strFromClient.startsWith("username:")){
String username = strFromClient.split("\\:")[1];
Register(username,client);
}
//群聊流程
if (strFromClient.startsWith("G:")){
String groupMsg = strFromClient.split("\\:")[1];
groupChat(groupMsg);
}
//私聊
if (strFromClient.startsWith("P:")){
String username = strFromClient.split("\\:")[1].split("\\-")[0];
String privateMsg = strFromClient.split("\\:")[1].split("\\-")[2];
privateChat(username,privateMsg);
}
//用户退出:1:byebye
if(strFromClient.contains("byebye")){
String username = strFromClient.split("\\:")[0];
userOffLine(username);
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void Register(String username,Socket socket){
clientLists.put(username,socket);
System.out.println("用户"+username+"上线了!当前聊天室人数为:"+clientLists.size());
try {
PrintStream out = new PrintStream(socket.getOutputStream(),true,"UTF-8");
out.println("注册成功");
out.println("当前聊天室人数为:"+clientLists.size());
} catch (IOException e) {
e.printStackTrace();
}
}
//群聊——遍历map,向每个客户端输出一遍
private void groupChat(String groupMsg) throws IOException {
Set<Map.Entry<String,Socket>> clientEntry = clientLists.entrySet();
Iterator<Map.Entry<String,Socket>> iterator = clientEntry.iterator();
while (iterator.hasNext()){
//取出每一个客户端实体
Map.Entry<String,Socket> client = iterator.next();
//拿到客户端输出流输出群聊信息
PrintStream out = new PrintStream(client.getValue().getOutputStream(),
true,"UTF-8");
out.println("群聊信息为:"+groupMsg);
}
}
//私聊
private void privateChat(String username,String privateMsg) throws IOException {
//取出username对应的Socket
Socket client = clientLists.get(username);
PrintStream out = new PrintStream(client.getOutputStream(),true,"UTF-8");
out.println("私聊信息为:"+privateMsg);
}
private void userOffLine(String username){
//删除map中的用户实体
clientLists.remove(username);
System.out.println("用户"+username+"已下线");
}
}
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(6666);
//使用线程池来同时处理多个客户端连接
ExecutorService executorService = Executors.newFixedThreadPool(20);
System.out.println("等待客户端连接");
for (int i=0;i<20;i++){
Socket client = serverSocket.accept();
System.out.println("有新的客户端连接,端口号为:"+client.getPort());
executorService.submit(new ExecuteClientRequest(client));
}
//关闭线程池与服务端
executorService.shutdown();
serverSocket.close();
}
}