1、服务器端socket
创建ServerSocket对象,绑定监听端口。
通过accept()方法监听客户端请求。
连接建立后,通过输入流读取客户端发送的请求信息。
通过输出流向客户端发送响应信息。
关闭响应的资源。
2、客户端socket
创建Socket对象,指明需要连接的服务器的地址和端口号。
连接建立后,通过输出流向服务器发送请求信息。
通过输入流获取服务器响应的信息。
关闭相应资源。
3、多线程实现服务器与多客户端之间通信步骤
服务器端创建ServerSocket,循环调用accept()等待客户端连接。
客户端创建一个socket并请求和服务器端连接。
服务器端接受客户端请求,创建socket与该客户建立专线连接。
建立连接的两个socket在一个单独的线程上对话。
服务器端继续等待新的连接。
4、服务端code
package socker;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @Description: Socket 服务端,用于模拟测试使用
*
* 用线程池的方式,算是一种成熟的方式。可以应用在生产中。
* ServerSocket有以下3个属性。
*
* SO_TIMEOUT:表示等待客户连接的超时时间。一般不设置,会持续等待。
* SO_REUSEADDR:表示是否允许重用服务器所绑定的地址。一般不设置
* SO_RCVBUF:表示接收数据的缓冲区的大小。一般不设置,用系统默认就可以了。
*
* @Author: LT
* @CreateDate: 2019/10/21 14:40
* @Version: 1.0.0
*/
public class SocketServerDemo {
public static void main(String args[]) throws Exception {
// 监听指定的端口
ServerSocket server = new ServerSocket(8888);
// server将一直等待连接的到来
System.out.println("server将一直等待连接的到来");
//如果使用多线程,那就需要线程池,防止并发过高时创建过多线程耗尽资源
ExecutorService threadPool = Executors.newFixedThreadPool(80);
while (true) {
Socket socket = server.accept();
Runnable runnable = () -> {
try {
// 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
StringBuilder sb = new StringBuilder();
while ((len = inputStream.read(bytes)) != -1) {
// 注意指定编码格式,发送方和接收方一定要统一,建议使用UTF-8
sb.append(new String(bytes, 0, len, "UTF-8"));
}
System.out.println("get message from client: " + sb);
OutputStream out=socket.getOutputStream();
String resp = "我是服务器";
out.write(resp.getBytes());
inputStream.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
};
threadPool.submit(runnable);
}
}
}
5、客户端code
package socker;
/**
* @Description: java类作用描述
* @Author: LT
* @CreateDate: 2019/10/21 13:59
* @Version: 1.0.0
*/
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
/**
* Socket客户端
*/
public static void main(String[] args) {
String requestMsg = "client xml or json 数据";
String address = "localhost";
int port = 8888;
send(address,port,requestMsg);
}
/**
* Socket 客户端请求
*
* @param address ip地址
* @param port 端口
* @param requestMsg 请求内容
*/
public static void send(String address,int port, String requestMsg) {
try {
//创建Socket对象
Socket socket=new Socket(address,port);
/**
* 根据输入输出流和服务端连接
* 1)获取一个输出流,向服务端发送信息
* 2)将输出流包装成打印流
* 3)关闭输出流
*/
OutputStream outputStream=socket.getOutputStream();
PrintWriter printWriter=new PrintWriter(outputStream);
printWriter.print(requestMsg);
printWriter.flush();
socket.shutdownOutput();
//获取一个输入流,接收服务端的信息
InputStream inputStream=socket.getInputStream();
//包装成字符流,提高效率
InputStreamReader inputStreamReader=new InputStreamReader(inputStream);
//缓冲区
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
StringBuffer sb = new StringBuffer();
//临时变量
String temp=null;
while((temp=bufferedReader.readLine())!=null){
sb.append(temp).append("\n");
}
System.out.println("客户端接收服务端发送信息:"+sb.toString());
//关闭相对应的资源
bufferedReader.close();
inputStream.close();
printWriter.close();
outputStream.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
参考文章:
java面试-线程池