https://blog.csdn.net/zeng308041977/article/details/76650935
https://blog.csdn.net/github_39655029/article/details/79953606
https://blog.csdn.net/qq_34178998/article/details/76958137
使用Java Socket+多线程实现简单服务器一对多个客户端响应
服务器
public class Server {
public static void main(String[] args) {
Socket socket=null;
try {
//设置服务器端口号
ServerSocket serverSocket=new ServerSocket(9999);
while (true){
System.out.println("等待客户端连接...");
//等待客户端连接
socket=serverSocket.accept();
//创建一个线程
ClientThread loginThread=new ClientThread(socket);
//开始线程
loginThread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端线程类
public class ClientThread extends Thread {
Socket socket=null;
public ClientThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
Scanner input=new Scanner(System.in);
InputStream is=null;
OutputStream os=null;
try {
//获取客户端的ip地址
System.out.println(socket.getInetAddress()+"已经成功连接到此服务器上."+df.format(new Date()));
//打开输入/输出流
is=socket.getInputStream();
os=socket.getOutputStream();
//获取客户端信息,即从输入流读取信息
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String info=null;
while (!((info= br.readLine()) ==null)){
System.out.println(socket.getInetAddress()+":"+info);
}
//服务器响应客户端
System.out.println("本机服务器:");
String reply="服务器成功回应!!";
os.write(reply.getBytes());
} catch (IOException e) {
System.out.println("网络出现了故障.....!!");
e.printStackTrace();
}finally {
try {
if(is!=null)
is.close();
if(os!=null)
os.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端1,客户端2,...类似,此处以客户端1为例
public class Client2 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
Socket socket= null;
OutputStream os=null;
InputStream is=null;
try {
while (true){
socket = new Socket("localhost",9999);
//打开输入/输出流
os=socket.getOutputStream();
is=socket.getInputStream();
//发送客户端登录信息,即向输出流写入信息
System.out.println("------欢迎进入聊天室------");
System.out.println("客户端:");
String info=input.next();
os.write(info.getBytes());
socket.shutdownOutput();
//接收服务器的响应,即从输入流中读取信息
String reply=null;
BufferedReader br=new BufferedReader(new InputStreamReader(is));
while (!((reply=br.readLine()) ==null)){
System.out.println("服务器:"+reply);
}
}
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if(is!=null)
is.close();
if(os!=null)
os.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
关于Socket中使用ReadLine的坑
结果运行的时候,当开启服务端和客户端后,在客户端的控制台 键盘输入 内容,服务端却没有显示内容
原因:
1.原来readLine()方法在进行读取一行时,只有遇到回车(\r)或者换行符(\n)才会返回读取结果,这就是“读取一行的意思”,重要的是readLine()返回的读取内容中并不包含换行符或者回车符;
2.由于在客户端使用的readLine()来读取用户输入,所以当用户按下回车键是,readLine() 返回读取内容,但此时返回的内容并不包含换行符(查看readLine()源码,会将\r,\n或者\r\n去除掉),而当在服务器端用readLine()再次读取时,由于读取的内容没有换行符,所以readLine()方法会一直阻塞等待换行符,这就是服务器端没有输出的原因。
解决方法:
在客户端每次输入回车后,手动给输入内容加入"\n"或"\r",再写入服务器;
注意:
1、误以为readLine()是读取到没有数据时就返回null(因为其它read方法当读到没有数据时返回-1),而实际上readLine()是一个阻塞函数,当没有数据读取时,就一直会阻塞在那,而不是返回null。没有数据时会阻塞,在数据流异常或断开时才会返回null
2、readLine()只有在数据流发生异常或者另一端被close()掉时,才会返回null值。
如果不指定buffer大小,则readLine()使用的buffer有8192个字符。在达到buffer大小之前,只有遇到"/r"、"/n"、"/r/n"才会返回。
3、使用socket之类的数据流时,要避免使用readLine(),以免为了等待一个换行/回车符而一直阻塞