流程:
- 服务端启动
- 客户端连接
- 每个客户端发送自己客户端名称给服务端,作为登录信息;
- 服务端主线程启动多个子线程,对应不同的客户端。收到登录信息后,返回给对应客户端信息“welcome!客户端名称”
服务端代码:
package Basic;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestSingleServer {
public static void main(String[] args) throws IOException {
//0.准备工作:创建处理客户端子线程池
ExecutorService threadPool = Executors.newFixedThreadPool(2);
//1.启动服务端
ServerSocket serverSocket = new ServerSocket(8989);
System.out.println("Server is Running!");
while (true){
//一旦有客户端连接,就返回一个socket对象
Socket socket = serverSocket.accept();
System.out.println("connection succeeded");
//5. 创建子线程处理客户端发送的消息
threadPool.execute(new ClientHandleThread(socket));
}
}
}
class ClientHandleThread implements Runnable{
private Socket socket;
public ClientHandleThread() {
}
public ClientHandleThread(Socket socket) {
this.socket = socket;
}
@Override
//5.0 处理:接收客户端信息并返回欢迎信息
public void run() {
try {
//5.1 接收客户端的登录信息
BufferedReader bis = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String clientInfo = bis.readLine();
System.out.println(clientInfo + " login success!");
BufferedWriter bos = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//5.2 返回给客户端欢迎登录信息
bos.write("welcome! " + clientInfo);
bos.newLine();
bos.flush();
socket.shutdownOutput();
bos.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端代码:
package Basic;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class TestClient {
public static void main(String[] args) throws IOException {
//2. 客户端与服务端建立连接
Socket socket = new Socket(InetAddress.getLocalHost(), 8989);
//3. 客户端发送自己的名称作为登录信息
Scanner scanner = new Scanner(System.in);
String clientName = scanner.next();
// 4.客户端发送自己的登录信息
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write(clientName);
bufferedWriter.newLine();
bufferedWriter.flush();
socket.shutdownOutput();
//6. 接收服务端返回的登录信息
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String s = bufferedReader.readLine();
if (s.contains("welcome"))
System.out.println("Congratulations!login success");
bufferedReader.close();
bufferedWriter.close();
}
}
启动一个服务端,启动两个客户端,分别输入Client A和Client B,执行结果如下:
小结:
- 信息传输本质上是流的作用,套接字socket是网络驱动层提供给应用程序编程的接口和一种机制,作用于硬件驱动和应用程序之间,数据接收和发送的原理如下:
socket数据发送:
socket数据接收:
- 无法同时启动两个Client时需要IDEA设置并行运行参数
- newLine()和shutdownOutput()必须添加,否则会流会一直阻塞。即客户端向服务端发送时,服务器会一直等待客户端的输出,既然服务器阻塞了,客户端等待着服务器的输出,也会被阻塞,所以导致客户端和服务端都被阻塞。
参数 - newLine()和shutdownOutput()必须添加,否则会流会一直阻塞。即客户端向服务端发送时,服务器会一直等待客户端的输出,既然服务器阻塞了,客户端等待着服务器的输出,也会被阻塞,所以导致客户端和服务端都被阻塞。
原理参考https://blog.csdn.net/u011403239/article/details/113806772


![[JAVA]网络编程基础(二) [JAVA]网络编程基础(二)](http://www.mshxw.com/aiimages/31/868157.png)
