Java TCP/UDP/HttpClient简例
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常用方法
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();
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();
其他
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");
获取网站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];
- dubbox 增加google-gprc/protobuf支持
- 统计02:怎样描绘数据
- ActiveMQ笔记(1):编译、安装、示例代码
- centos ssh终端下高亮显示git分支名
- Django ORM模型:想说爱你不容易
- IE7下元素的 'padding-top' 遇到 'clear' 特性在某些情况下复制到 'padding-bottom'
- IE7下元素的 'padding-top' 遇到 'clear' 特性在某些情况下复制到 'padding-bottom'
- ARM处理器:开放者的逆袭
- 从5个方面对比微信小程序和App
- ActiveMQ笔记(7):如何清理无效的延时消息?
- JS魔法堂:再识Bitwise Operation & Bitwise Shift
- Hadoop(十三)分析MapReduce程序
- mac机上搭建php56/nginx 1.8.x/thinkphp 3.2.x/gearman扩展/seaslog扩展/redis扩展环境
- 基础野:细说无符号整数
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- oracle补充
- 搞它!!!Linux系统LVM原理及磁盘配额(PV、VG、LV、PE的关系,手把手教你,嘴对嘴的传达)
- 搞它!!!linux网络服务基本设置命令合集
- 搞它!!!Linux系统上DHCP服务器的配置(理论加实验,分分钟搞定!!!)
- 搞它!!!Linux——引导、排障及修复
- 排障集锦:九九八十一难之第一难!linux发现交换文件无法打开文件!
- 排障集锦:九九八十一难之第三难!搭建DNS错误:Host xxxx not found: 2(SERVFAIL)
- 搞它!!!linux远程控制 openssh
- 搞它!!!Linux构建远程YUM仓库与NFS共享存储服务
- 排障集锦:九九八十一难之第四难! yum下载软件发现已存在的 RPM 数据库问题,无法下载,
- 搞它!!!深入了解DNS域名解析服务,教你搭建一个属于自己的DNS服务器(正向解析、反向解析、泛域名解析、邮件交换解析、别名解析、分离解析,主从结构解析)
- Nginx Ingress 高并发实践
- 搞它!!!2020年了,你还不会PXE+kickstart 一键式部署安装系统么
- shell脚本快速入门系列—————— shell脚本编程规范
- shell脚本快速入门系列之------条件语句(if、case)