文章目录

  • ​​TCP​​
  • ​​ServerSocket构造函数​​
  • ​​ServerSocke常用方法​​
  • ​​ServerSocke注意事项​​
  • ​​backlog​​
  • ​​UDP​​
  • ​​DatagramSocket构造函数​​
  • ​​HttpClient​​
  • ​​添加依赖​​
  • ​​HttpClient使用​​
  • ​​**1、新建httpClient对象**​​
  • ​​**2、创建http请求对象**​​
  • ​​**3、cookie策略(cookieSpec)**​​
  • ​​**4、执行get请求**​​
  • ​​**5、执行post请求**​​
  • ​​**6、解析response**​​
  • ​​得到html code​​
  • ​​得到http状态码​​
  • ​​得到response header​​
  • ​​得到inputstream​​
  • ​​管理cookie​​
  • ​​得到当前所有cookie​​
  • ​​使用CookieStore实例​​
  • ​​使用HttpClientContext,使用内置CookieStore​​
  • ​​清除所有cookie​​
  • ​​自定义cookie​​
  • ​​其他​​
  • ​​**UrlEncodedFormEntity**​​
  • ​​**StringEntity**​​
  • ​​EntityUtils.toString​​
  • ​​HttpContext​​
  • ​​获取网站charset​​
  • ​​判断访问目标网站是否需要代理​​
  • ​​JESSIONID​​

TCP

ServerSocket构造函数

  • ​ServerSocket():​​创建非绑定服务器套接字。
  • ​ServerSocket(int port):​​创建绑定到特定端口的服务器套接字。
  • ​ServerSocket(int port, int backlog):​​利用指定的backlog创建服务器套接字并将其绑定到指定的本地端口号。
  • ​ServerSocket(int port, int backlog, InetAddress bindAddress):​​使用指定的端口、侦听backlog和要绑定到的本地I地址创建服务器。这种情况适用于计算机上有多块网卡和多个IP地址的情况,用于可以明确规定ServerSocket在哪块网卡或P地址上等待客户的连接请求。

ServerSocke常用方法

Java TCP/UDP/HttpClient简单理解_java

ServerSocke注意事项

  • ​accept()​​方法会阻塞线程的继续执行,直到接收到客户的呼叫。
  • 调用​​ServerSocket​​​类的​​accept()​​​方法会返回一个和客户端​​Socket​​​对象相连接的​​Socket​​对象
  • 服务器端的​​Socket​​​对象使用​​getOutputStream()​​​方法获得的输出流将指向客户端​​Socket​​​对象使用​​getInputStream()​​方法获得的那个输入流;
  • 同样,服务器端的​​Socket​​​对象使用​​getInputStream()​​​方法获得的输入流将指向客户端​​Socket​​​对象使用​​getOutputStream()​​方法获得的那个输出流。
  • 也就是说,当服务器向输出流写入信息时,客户端通过相应的输入流就能读取,反之亦然。
// server
BufferedReader reader;
Socket socket;
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("创建成功");
while (true){
socket = serverSocket.accept();
System.out.println("连接成功");
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
try {
String info = null;
while ((info = reader.readLine()) != null) {
System.out.println(info);
}
} catch (Exception e){
}
if (reader != null) reader.close();
if (socket != null) socket.close();
}

// client
PrintWriter pw;
Socket socket = new Socket("localhost", 8080);
System.out.println("连接成功");
pw = new PrintWriter(socket.getOutputStream(), true);
pw.write("ok");
pw.print('x');
if(pw!=null)
pw.close();
if(socket!=null)
socket.close();

Java TCP/UDP/HttpClient简单理解_UDP_02

backlog

​ 服务端socket处理客户端socket连接是需要一定时间的。ServerSocket有一个队列,存放还没有来得及处理的客户端Socket,这个队列的容量就是backlog的含义。如果队列已经被客户端socket占满了,如果还有新的连接过来,那么ServerSocket会拒绝新的连接。也就是说backlog提供了容量限制功能,避免太多的客户端socket占用太多服务器资源。
​ 客户端每次创建一个Socket对象,服务端的队列长度就会增加1个。服务端每次accept(),就会从队列中取出一个元素。

UDP

  • 发送数据包:
  • 使用​​DatagramSocket()​​创建一个数据包套接字。
  • 使用​​DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)​​创建要发送的数据包。
  • 使用​​DatagramSocket​​​类的​​send()​​方法发送数据包。
  • 接收数据包:
  • 使用​​DatagramSocket(int port)​​创建数据包套接字,绑定到指定的端口。
  • 使用​​DatagramPacket(byte[] buf, int length)​​创建字节数组来接收数据包。
  • 使用​​DatagramPacket​​​类的​​receive()​​​方法接收​​UDP​​包。
  • ​DatagramSocket​​​类的​​receive()​​方法接收数据时,如果还没有可以接收的数据,在正常情况下​​receive()​​方法将阻塞,一直等到网络上有数据传来,​​receive()​​方法接收该数据并返回。
  • 如果网络上没有数据发送过来,​​receive()​​方法也没有阻塞,肯定是程序有问题,大多数是使用了一个被其他程序占用的端口号。

DatagramSocket构造函数

  • ​DatagramSocket()​​:构造数据报套接字并将其绑定到本地主机上任何可用的端口。
  • ​DatagramSocket(int port)​​:创建数据报套接字并将其绑定到本地主机上的指定端口。
  • ​DatagramSocket(int port,InetAddress addr)​​:创建数据报套接字并将其绑定到指定的本地地址。

接收程序时,必须指定一个端口号,不要让系统随机产生,此时可以使用第二种构造函数。在发送程序时,通常使用第一种构造函数,不指定端口号,这样系统就会为我们分配一个端口号。

// server
byte[] data = new byte[1024];
DatagramSocket socket = new DatagramSocket(8080);
InetAddress inetAddress = InetAddress.getLocalHost();
DatagramPacket packet = new DatagramPacket(data, data.length);
socket.receive(packet);
System.out.println(Arrays.toString(data));

// client
byte[] data = "test".getBytes();
DatagramSocket socket = new DatagramSocket();
InetAddress inetAddress = InetAddress.getLocalHost();
DatagramPacket packet = new DatagramPacket(data, data.length, inetAddress, 8080);
socket.send(packet);


HttpClient

添加依赖

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.12</version>
</dependency>

HttpClient使用

使用​​HttpClient​​发送请求主要分为以下几个步骤:

  • 创建 ​​CloseableHttpClient​​​对象或​​CloseableHttpAsyncClient​​对象,前者同步,后者为异步
  • 创建​​Http​​请求对象
  • 调用​​execute​​​方法执行请求,如果是异步请求在执行之前需调用​​start​​方法

1、新建httpClient对象

// 最好使用static修饰,以保证用同一个client对象处理请求,以保存进度  
static CloseableHttpClient client = HttpClients.createDefault();
// 第二种方法里添加一些网络访问选项设置
static CloseableHttpClient httpClient=HttpClients.custom().build();

2、创建http请求对象

HttpGet get = new HttpGet("http://www.baidu.com");

3、cookie策略(cookieSpec)

参数为​​cookiespecs​​的一些字段。

作用:

  • 如果网站​​header​​中有​​set-cookie​​字段时,采用默认方式可能会被​​cookie reject​​,无法写入​​cookie​​。将此属性设置成​​CookieSpecs.STANDARD_STRICT​​可避免此情况。
  • 如果要想忽略​​cookie​​访问,则将此属性设置成​​CookieSpecs.IGNORE_COOKIES​​。

**tips:**注意网站编码,否则容易出现乱码

// 设置超时及cookie策略
static RequestConfig config = RequestConfig.custom()
.setConnectTimeout(6000)
.setSocketTimeout(6000)
.setCookieSpec(CookieSpecs.STANDARD)
.build();
get.setConfig(config);

4、执行get请求

新建httpget对象 -> 用httpClient执行- > 解析返回的response得到自己需要的内容

// 执行请求,获取response
HttpResponse response = client.execute(get);
// 状态码
int statusCode = response.getStatusLine().getStatusCode();
System.out.println(statusCode);
// 用于得到返回的文件头
Header[] headers = response.getAllHeaders();
System.out.println(Arrays.toString(headers));
// 在后面参数输入网站的编码,一般为utf-8。返回的html代码,避免发生编码错误
String html = new String(EntityUtils.toString(response.getEntity()).getBytes("iso8859-1"), "gb2312");
System.out.println(html);

5、执行post请求

新建post对象 -> 新建需要的表单页 -> 将表单内容设置入请求中 -> 执行并获得response

CloseableHttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost("http://www.baidu.com");
// 设置请求头header
post.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36");
post.setHeader("Connection", "keep-alive");
// 设置表单键值对
List<NameValuePair> list = new ArrayList<>();
list.add(new BasicNameValuePair("key1", "value1"));
list.add(new BasicNameValuePair("key2", "value2"));
// 把输入数据编码成合适的内容
HttpEntity entity = new UrlEncodedFormEntity(list, "utf-8");
post.setEntity(entity);
HttpResponse response = client.execute(post);
String html = EntityUtils.toString(response.getEntity());
System.out.println(html);

6、解析response

得到html code

String responseHtml = EntityUtils.toString(response.getEntity());

得到http状态码

int statusCode = response.getStatusLine().getStatusCode();

得到response header

response.getFirstHeader("key"); // 得到第一个名字为key的header  
response.getHeaders("key"); // 得到名字为key的所有header,返回一个数组
response.getLastHeader("key");

得到inputstream

下载网络部分资源的时候有可能会对cookie有要求,此时需要用到httpClient来下载。例如验证码等等。

InputStream inputStream = response.getEntity().getContent();

管理cookie

​ ​​httpClient​​​里默认自动管理​​cookie​​​,如果想要提取​​cookie​​​或者发送自定义的​​cookie​​​,则需要在​​httpClient​​​对象初始化时设置一个默认的​​cookiestore​​​来保存。方法见初始化​​httpClient​​​对象里的​​setDefaultCookieStore​​。

​ ​​httpclient4.x​​自带维护回话的功能,只要使用同一个​httpclient​​且未关闭连接,就可以使用相同的回话来访问其他要求登陆验证的服务。 如果需要使用​​HttpClient​​​池,并且想要做到一次登陆的会话供多个​​httpClient​​连接使用,就需要自己保存回话信息。

​ 客户端的回话信息是保存在​​cookie​​​中的​​(JESSIONID)​​​,所以只需要将登陆成功返回的​​cookie​​​复制到各个​​HttpClient​​​使用即可。 使用​​Cookie​​​的方法有两种,可以自己使用​​CookieStore​​​来保存,也可以通过​​HttpClientContext​​上下文来维持。

得到当前所有cookie

使用CookieStore实例
// 创建cookie store的本地实例
CookieStore cookieStore=new BasicCookieStore();
CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
// 构建get对象
HttpGet get=new HttpGet("https://www.baidu.com/");
// 添加请求头header
get.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36");
// 执行请求
httpClient.execute(get);
// 获取Cookie
List<Cookie> list = cookieStore.getCookies();
使用HttpClientContext,使用内置CookieStore
CloseableHttpClient httpClient = HttpClients.createDefault();
// 构建get对象
HttpGet get=new HttpGet("https://www.baidu.com/");
// 添加请求头header
get.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36");
// 创建HttpClient上下文
HttpClientContext context=HttpClientContext.create();
// 执行请求
httpClient.execute(get,context);
// 获取Cookie
List<Cookie> list = context.getCookieStore().getCookies();

清除所有cookie

cookieStore.clear();

自定义cookie

CookieStore cookieStore = new BasicCookieStore(); 
CloseableHttpClient client = HttpClients.custom()
.setDefaultCookieStore(cookieStore)
.build();
BasicClientCookie cookie = new BasicClientCookie("name", "value");
// 设置cookie内容
cookie.setPath("/"); // 路径
cookie.setVersion(0); // 版本
cookie.setDomain("domain"); // 域名
cookie.setExpiryDate(new Date()); // 有效时间
// 添加cookie进来
cookieStore.addCookie(cookie);
client.execute(post);

最后通过按得到addCookie将其加入cookieStore。如有相同的name的cookie将会覆盖,类似hashmap的put操作。

其他

UrlEncodedFormEntity

由一系列url编码对组成的实体。这在发送HTTP POST请求时通常很有用。

UrlEncodedFormEntity会以字符串键值对形式传给后台,即:{“a”:“value1”, “b”:“value2”},传给java方法,接收到的参数是:a=value1&b=value2,即它不支持json参数传递;

StringEntity

而StringEntity传参,后台接收到的依然是 {“a”:“value1”, “b”:“value2”},即StringEntity能传递json。

当然,如果你传递的就是一个普通的字符串,StringEntity也是支持的。

String param = "{\"a\":\"value1\", \"b\":\"value2\"}";
StringEntity entity = new StringEntity(param, ContentType.create("application/json", "UTF-8"));
post.setEntity(entity);

EntityUtils.toString

使用指定编码格式,将网页中文内容转换成对应的字符集。

String Ori = EntityUtils.toString(httpResponse.getEntity(), "iso8859-1");

再转换为统一的utf-8

String entity = new String(Ori.getBytes(), "utf-8");

HttpContext

逻辑会话相关的多个请求序列应该使用同一个HttpContext实例,这样就可以让会话信息和状态信息在多个请求之间自动广播。

获取网站charset

String CharsetString = EntityUtils.toString(response.getEntity());
// 解析
Document CharsetDocument = Jsoup.parse(CharsetString);
// 字符集信息提取
String charset = CharsetDocument.select("meta[http-equiv=Content-Type]").attr("content").split("=")[1];

判断访问目标网站是否需要代理

private boolean isNeedProxy() {  
boolean result = true;
URL url;
try {
url = new URL("http://apkpure.com/");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(6000);
int i = conn.getContentLength();
if (i > 0) {
result = false;
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
}

JESSIONID

​ ​​jsessionid​​​就是用来判断当前用户对应于哪个​​session​​​。换句话说服务器识别​​session​​​的方法是通过​​jsessionid​​​来告诉服务器该客户端的​​session​​在内存的什么地方。

//JSSIONID
String setCookie - httpResponse.getFirestHeader("Set-Cookie").getValue();
String JESSIONID = setCookie.substring("JESSIONID=".length(),setCookie.indexOf(";"));