1、介绍
Socket的本质是编程接口,是对TCP/IP协议的具体实现,各种编程语言均有自己的实现,可以直接给程序员调用使用。本质是建立端口与端口间的网络通信。
在java的实际开发中,很少会自己直接使用Socket编程,一般借助第三方写好的工具类或框架。在阅读第三方框架工具的源码中,可能会存在Socket的操作。
2、流程图解
3、代码演示
服务端
public class DemoServer {
public static void main(String[] args) throws IOException {
//创建服务端socket,监听tcp 8080端口。
ServerSocket serverSocket = new ServerSocket(8080);
while (true){
//阻塞等待tcp客户端连接,连接好后会创建返回一个Socket对象。
Socket clientSocket = serverSocket.accept();
System.out.println(clientSocket.getInetAddress()+" "+clientSocket.getPort());
handleSocket(clientSocket);
}
}
//新建线程处理连接的Socket客户端发送的消息
private static void handleSocket(Socket socket){
new Thread(()->{
byte[] bufferBytes = new byte[1024];
InputStream in = null;
OutputStream out = null;
try {
in = socket.getInputStream();
out = socket.getOutputStream();
while (true){
//阻塞读取tcp客户端发送的消息
int readCount = in.read(bufferBytes);
if(readCount!=-1){
String str = new String(bufferBytes, 0, readCount);
System.out.println("服务端接收到的信息:"+str);
//回送消息给客户端
out.write(bufferBytes,0,readCount);
out.flush();
}else {
System.out.println("socket客户端异常断开");
break;
}
}
}catch (IOException e){
e.printStackTrace();
}finally {
closeIO(out);
closeIO(in);
closeIO(socket);
}
}).start();
}
//关闭流方法
private static void closeIO(Closeable io){
if(io!=null){
try{
io.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
客户端
public class DemoClient {
public static void main(String[] args) throws IOException {
//创建Socket
Socket socket = new Socket();
//Socket连接指定ip、port
socket.connect(new InetSocketAddress("127.0.0.1", 8080));
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
handleMsg(in);
Scanner scanner = new Scanner(System.in);
boolean flag = true;
while (flag){
String str = scanner.next();
if("exit".equals(str)){
flag = false;
}
out.write(str.getBytes());
out.flush();
}
closeIO(out);
closeIO(in);
closeIO(socket);
}
//新建线程处理服务端Socket发送的消息
public static void handleMsg(InputStream in){
new Thread(()->{
try {
byte[] bufferBytes = new byte[1024];
while (true){
int read = in.read(bufferBytes);
if(read!=-1){
String str = new String(bufferBytes, 0, read);
System.out.println("客户端接收到消息:"+str);
}else {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
closeIO(in);
}
}).start();
}
//关闭流方法
private static void closeIO(Closeable io){
if(io!=null){
try{
io.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
4、存在问题
按照上面的编码方式,每建立一个socket连接,服务端都会新建一个线程处理与之对应的socket数据读写。
若服务端同时接收太多的socket连接,会让服务端消耗过多内存,大量的线程抢占CPU资源也会增大服务器压力。所谓的C10K(connect 10 kilo=>万连接场景)、C10M(connect 10 million=>千万连接场景)。