Socket是什么呢?

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。

在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。
 UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。

Socket 原理

Socket 连接,至少需要一对套接字,分为 clientSocket,serverSocket 连接分为3个步骤:

(1) 服务器监听:服务器并不定位具体客户端的套接字,而是时刻处于监听状态;

(2) 客户端请求:客户端的套接字要描述它要连接的服务器的套接字,提供地址和端口号,然后向服务器套接字提出连接请求;

(3) 连接确认:当服务器套接字收到客户端套接字发来的请求后,就响应客户端套接字的请求,并建立一个新的线程,把服务器端的套接字的描述发给客户端。一旦客户端确认了此描述,就正式建立连接。而服务器套接字继续处于监听状态,继续接收其他客户端套接字的连接请求.

过程图解:

先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。

在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。

客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

实例展示:

服务器端:

package com.socket.test;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket; public class SocketServer {
public static void main(String[] args) throws Exception {
// 监听指定的端口
int port = 55533;
ServerSocket server = new ServerSocket(port); // server将一直等待连接的到来
System.out.println("server将一直等待连接的到来");
Socket socket = server.accept();
// 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
StringBuilder sb = new StringBuilder();
//只有当客户端关闭它的输出流的时候,服务端才能取得结尾的-1
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 outputStream = socket.getOutputStream();
outputStream.write("Hello Client,I get the message.".getBytes("UTF-8")); inputStream.close();
outputStream.close();
socket.close();
server.close();
}
}

当读取完客户端的消息后,打开输出流,将指定消息发送回客户端

客户端:

package com.socket.test

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket; public class SocketClient {
public static void main(String args[]) throws Exception {
// 要连接的服务端IP地址和端口
String host = "127.0.0.1";
int port = 55533;
// 与服务端建立连接
Socket socket = new Socket(host, port);
// 建立连接后获得输出流
OutputStream outputStream = socket.getOutputStream();
String message = "你好 fuwuqiduan";
socket.getOutputStream().write(message.getBytes("UTF-8"));
//通过shutdownOutput高速服务器已经发送完数据,后续只能接受数据
socket.shutdownOutput(); 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 server: " + sb); inputStream.close();
outputStream.close();
socket.close();
}
}

客户端也有相应的变化,在发送完消息时,调用关闭输出流方法,然后打开输出流,等候服务端的消息。

服务器段优化

在上面的例子中,服务端仅仅只是接受了一个Socket请求,并处理了它,然后就结束了,但是在实际开发中,一个Socket服务往往需要服务大量的Socket请求,那么就不能再服务完一个Socket的时候就关闭了,这时候可以采用循环接受请求并处理的逻辑:

package com.socket.test
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket; public class SocketServer {
public static void main(String args[]) throws IOException {
// 监听指定的端口
int port = 55533;
ServerSocket server = new ServerSocket(port);
// server将一直等待连接的到来
System.out.println("server将一直等待连接的到来"); while(true){
Socket socket = server.accept();
// 建立好连接后,从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);
inputStream.close();
socket.close();
} }
}

这种一般也是新手写法,但是能够循环处理多个Socket请求,不过当一个请求的处理比较耗时的时候,后面的请求将被阻塞,所以一般都是用多线程的方式来处理Socket,即每有一个Socket请求的时候,就创建一个线程来处理它。

  不过在实际生产中,创建的线程会交给线程池来处理,为了:

  • 线程复用,创建线程耗时,回收线程慢
  • 防止短时间内高并发,指定线程池大小,超过数量将等待,方式短时间创建大量线程导致资源耗尽,服务挂掉
package com.socket.test

import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class SocketServer {
public static void main(String args[]) throws Exception {
// 监听指定的端口
int port = 55533;
ServerSocket server = new ServerSocket(port);
// server将一直等待连接的到来
System.out.println("server将一直等待连接的到来"); //如果使用多线程,那就需要线程池,防止并发过高时创建过多线程耗尽资源
ExecutorService threadPool = Executors.newFixedThreadPool(100); 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);
inputStream.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
};
threadPool.submit(runnable);
} }
}

借鉴网址:https://www.cnblogs.com/yiwangzhibujian/p/7107785.html

最新文章

  1. ORACLE应用调优:请避免SQL做大量循环逻辑处理
  2. iOS 运行时
  3. 安卓开发NDK环境搭建
  4. plain framework 1 参考手册 入门指引之 简明教程
  5. ajax技术的应用?
  6. [转]浅谈https\ssl\数字证书
  7. CLIP PATH (MASK) GENERATOR是一款在线制作生成clip-path路径的工具,可以直接生成SVG代码以及配合Mask制作蒙板。
  8. HDOJ/HDU 2700 Parity(奇偶判断~)
  9. Oracle优化技术
  10. Jar包转成Dll的方式(带嵌套的jar也能做)
  11. 我的.gitignore下配置。存在这里一下。日后有空研究研究!
  12. Linux环境下执行java -jar xxx.jar命令如何让springboot项目在后台运行
  13. 当使用cokie进行数据交互时候,cookie只需存储该对象的id即可不需要存放其他数据;只需在写个接口根据cookie里面的对象id来创建对象
  14. [转][MVC4]ASP.NET MVC4+EF5(Lambda/Linq)读取数据
  15. Redis五大数据类型常用命令脑图
  16. Integer类之equals与hashCode
  17. 2018.06.30 BZOJ 3932: [CQOI2015]任务查询系统(主席树)
  18. 2018.09.05 任务安排(斜率优化dp)
  19. Inside GDALAllRegister之二: 自动加载驱动
  20. CodeForces 19D Points (线段树+set)

热门文章

  1. QUIC/HTTP3 协议简析
  2. Myeclipse启动WebLogic 总是报账号密码无效<Authentication denied: Boot identity not valid
  3. P2220 [HAOI2012]容易题【快速幂】
  4. JavaScript基础函数的配置对象Configuration Objects(020)
  5. 洛谷 P1194 【买礼物】
  6. 113资讯网:安装程序进入Admin后台出现:SQLSTATE[HY000] [1045] Access denied for user'root'@'localhost' (using password: YES)
  7. 2020年,web前端还好找工作吗?
  8. (私人收藏)Vue.js手册及教程
  9. java语言进阶(七)_Lambda表达式
  10. java语言进阶(三)_List_Set_数据结构_Collections