Java编程 VI 网络编程

Socket

socket提供了与外部网络通信的网络接口

InetAddress

InetAddress 提供了一些获取ip地址信息的方法

1
2
3
4
5
6
static InetAddress getByName(String host)     
static InetAddress[] getAllByName(String host) // 为给定主机名创建一个InetAddress对象
static InetAddress getLocalHost() // 为本地主机创建一个InetAddress对象
byte[] getAddress() // 获取数字型地址的字节数组
String getHostAddress() // 以字符串返回主机地址
String getHostName() // 返回主机名

创建一个Socket Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.io.* ;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

class Echoserver{
public static void main(String[] args) throws Exception{
try(var s = new ServerSocket(8189)){
try(Socket incoming = s.accept()){
InputStream inStream = incoming.getInputStream();
OutputStream outStream = incoming.getOutputStream();
try(var in = new Scanner(inStream, StandardCharsets.UTF_8)){
var out = new PrintWriter(new OutputStreamWriter(outStream,StandardCharsets.UTF_8),true);
out.println("Hello! Enter BYE to exit.");
var done = false;
while(!done&&in.hasNextLine()){
String line = in.nextLine();
out.println("Echo:"+line);
if(line.trim().equals("BYE"))
done = true;
}
}
}

};
}

}

当前的服务器 只能接受一个用户请求,使用 多线程将它改造为接受多个用户请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.io.* ;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

class Echoserver{
public static void main(String[] args) throws Exception{
try(var s = new ServerSocket(8189)){
int i = 0;
while(true){
Socket incoming = s.accept();
Runnable thread_mission = new ThreadedHandler(incoming);
Thread t = new Thread(thread_mission);
t.start();
}
}
}

}

class ThreadedHandler implements Runnable {
private Socket incoming;
ThreadedHandler(Socket incoming){
this.incoming = incoming;
}
@Override
public void run(){
try {
InputStream inStream = incoming.getInputStream();
OutputStream outStream = incoming.getOutputStream();
try(var in = new Scanner(inStream, StandardCharsets.UTF_8)){
var out = new PrintWriter(new OutputStreamWriter(outStream,StandardCharsets.UTF_8),true);
//flush 强制将缓存区数据发送出去。
out.println("Hello! Enter BYE to exit.");
var done = false;
while(!done&&in.hasNextLine()){
String line = in.nextLine();
out.println("Echo:"+line);
if(line.trim().equals("BYE"))
done = true;
}
}catch(Exception e){
e.printStackTrace();
}
} catch (Exception e) {
}
}
}

从这里可以看出TCP端口虽然是固定的,但操作系统通过为每个连接分配唯一的 socket(基于四元组标识)来实现多个连接共用一个监听端口。应用程序通常为每个 socket 启动一个线程或事件循环进行数据处理,从而实现高并发连接的处理。

半关闭

1
2
3
4
5
6
7
8
9
10
11
12
tar (var socket = new Socket(host,port)){
var in = new Scanner(socket.getInputStream(),StandardCharsets.UTF_8);
var writer = new PrintWriter(socket.getOutputStream());
writer.print(...);
writer.flush();
socket.shutdownOutput();
while(in.hasNextLine() !=null )
{
String line = in.next.line;
...
}
}

URL

java提供了url 对象来对web 数据的访问地址进行封装

1
2
InputStream inStream = url.OpenStream();
var in = new Scanner(inStream,StandardCharsets.UTF-8);

urlconnection

从url中获取更多的内容

1
URLConnection connection = url.openConnecton();

URL

1
2
InputStream openStream()
URLConnection openConnection()

URLConnection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void setDoInput()
// 设置接收数据状态
boolean getDoInput()
// 获取接收护数据的状态
void setDoOutput()
// 设置创建发送流
boolean getDoOutput()
// 获取发送流的状态
void setIfModifiedSince(long time)
// 获取某个时间点依赖修改的数据
long getIfModifiedSince()

void setConnectTimeout()
int getConnectTimeout()
// 设置连接的超时时间
int getReadTimeout()
void setReadTimeout()
// 设置读取数据的超时时间
void setRequestProperty(String key ,String value)
Map<String,List<String>> getRequestProperties()
// 设置 /读取 请求头中的属性
void connect()
// 连接远程资源并获取头部信息
Map<String, List<String>> getHeaderFields()
// 获取响应头映射表
String getHeaderFileKey(int n)
String getHeaderField(int n)
// 获取第n个响应头的键/值信息
int getContentLength()
// 获取内容长度
String getConnentType()
// 获取内容的类型
String getContentEncoding()
// 获取编码信息
long getDate()
long getExpiration()
long getLastModifed()
// 获取创建日期,超时日期和最后一次修改的日期
InputStream getInputStream()
// 获取一个输入流
OutputStream getOutputStream()
// 获取一个输出流
Object getContent()

HTTP 客户端

1
2
3
4
5
6
HttpClient client = HttpClient.newHttpClient()
HttpClient client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.ALWAYS).build()
HttpClient client = HttpClient.newBuilder().uri(new URI("<http://horstmann.com>")).GET().build()
// 创建 get请求
HttpClient client = HttpClient.newBuilder().uri(new URL(url)).POST(HttpRequest.BodyPublishers.ofString(jsonString)).build())
// 创建 post请求

通过 HttpResponse 接收客户端响应

HttpResponse<T> 类 接收一个 经过响应处理器(HttpResponse.BodyHandlers.ofString())处理的响应对象

1
HttpResponse<String> response = client.send(request,HttpResponse.BodyHandlers.ofString());

通过HttpResponses 还可以获取头信息和状态码

1
2
3
4
5
6
7
8
9
10
11
12
int status = response.statusCode();       // 获取状态码信息
HttpHeaders responseHeaders = response.headers(); // 获取响应头
Map<String,List<String>> headerMap = responseHeaders.map(); // 获取响应头的映射信息
Optional<String> lastModified = responseHeaders.firstValue("Last-Modified"); // 获取具体的字段

ExecutorSevice executor = Executor.newCachedThreadPool(); //创建线程池
HttpClient client = HttpClient.newBuilder().executor(executor).build(); // 创建client放入线程池

HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenAccept(response->); // 创建异步响应,创建请求,使用client 发送该请求,并通过thenAccept
// 来处理得到响应后的任务

方法签名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
HttpClient 
static HttpClient newHttpClient()
// 创建一个默认的HttpClient对象
static HttpClient.Builder newBuilder()
// 在流中创建一个HttpClient 对象
<T> HttpResponse<T> send(HttpRequest request , HttpResponse.BodyHandler<T> responseBodyHandler)
// client 发送一个请求,返回一个HttpResponse对象
<T> CompletableFuture<HttpResponse<T>> sendAsync(HttpRequest request, HttpResponse.BodyHandler
// 使用sendAsync 发送一个异步请求, 后续使用thenAccept接收异步响应的处理
<T> responseBodyHandler )

HttpClient.Builder
HttpClient build()
// 创建一个HttpClient 实例(终结方法)
HttpClient.Builder followRedirects(HttpClient.Redirect policy(ALWAYS, NEVR,NORMAL))
// 设置客户端接收重定向的策略
HttpClient.Builder executor(Executor executor)
// 将客户端加入指定的执行器

HttpRequest
HttpRequest.Builder newBuilder()
// 流式调用创建一个request请求
HttpRequest.Builder
HttpRequest build()
// 创建一个HttpRequest 实例 (终结方法)
HttpRequest.Builder uri(URI uri)
// 流式调用中指定uri
HttpRequest.Builder GET()
// 指定http get方法
HttpRequest.Builder DELETE()
// 指定 http delete 方法
HttpRequest.Builder POST(HttpRequest.BodyPublisher bodyPublisher)
// 指定 http post 方法 接收一个请求体
HttpRequest.Builder PUT(HttpRequest.BodyPublisher bodyPublisher)
// 指定 http put 方法 接收一个请求头
HttpResponse
T body()
// 产生响应体
int statusCode()
// 状态码
HttpHeaders headers()
// 响应头

HttpHeaders
Map<String , List<String>> map()
// 通过map 获取 httpheaders 的映射
Optional<String> firstValue(String name)
// 获取 头中属性的第一个值

Java编程 VI 网络编程
http://gadoid.io/2025/04/29/Java编程-VI-网络编程/
作者
Codfish
发布于
2025年4月29日
许可协议