参考
计算机网络基础
-
IP和端口号
-
端口号 0- 65535
-
IPV4 和 IPV6
-
TCP 三次握手,四次挥手
-
UDP 无连接协议,不会建立可靠传输
Socket技术
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket;
public class Server { public static void main(String[] args) { try(ServerSocket server = new ServerSocket(8080)){ System.out.println("正在等待客户端连接..."); while (true){ Socket socket = server.accept(); System.out.println("客户端已连接,IP地址为:"+socket.getInetAddress().getHostAddress()); } }catch (IOException e){ e.printStackTrace(); } } }
|
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket;
public class Client { public static void main(String[] args) { try (Socket socket = new Socket("localhost", 8080)){ System.out.println("已连接到服务端!"); }catch (IOException e){ System.out.println("服务端连接失败!"); e.printStackTrace(); } } }
|
Socket数据传输
实现Socket在TCP协议上的一次连接
import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner;
public class Client { public static void main(String[] args) { try (Socket socket = new Socket("localhost", 8080); Scanner scanner = new Scanner(System.in)){ System.out.println("已连接到服务端!"); OutputStream stream = socket.getOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(stream); System.out.println("请输入要发送给服务端的内容:"); String text = scanner.nextLine(); writer.write(text+'\n'); writer.flush(); System.out.println("数据已发送:"+text); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); System.out.println("收到服务器返回:"+reader.readLine()); }catch (IOException e){ System.out.println("服务端连接失败!"); e.printStackTrace(); }finally { System.out.println("客户端断开连接!"); } } }
|
OutputStream
还提供了一个flush()
方法,它的目的是将缓冲区的内容真正输出到目的地。
因为向磁盘、网络写入数据的时候,出于效率的考虑,操作系统并不是输出一个字节就立刻写入到文件或者发送到网络,而是把输出的字节先放到内存的一个缓冲区里(本质上就是一个byte[]
数组),等到缓冲区写满了,再一次性写入文件或者网络。对于很多IO设备来说,一次写一个字节和一次写1000个字节,花费的时间几乎是完全一样的,所以OutputStream
有个flush()
方法,能强制把缓冲区内容输出。
立刻调用flush()
,不管当前缓冲区是否已满,强迫操作系统把缓冲区的内容立刻发送出去。
https://www.liaoxuefeng.com/wiki/1252599548343744/1298069169635361
import java.io.*; import java.net.ServerSocket; import java.net.Socket;
public class Server { public static void main(String[] args) { try(ServerSocket server = new ServerSocket(8080)){ System.out.println("正在等待客户端连接..."); Socket socket = server.accept(); System.out.println("客户端已连接,IP地址为:"+socket.getInetAddress().getHostAddress()); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); System.out.print("接收到客户端数据:"); System.out.println(reader.readLine()); socket.close(); }catch (IOException e){ e.printStackTrace(); } } }
|
服务器与客户端建立连接后返回信息给客户端
public static void main(String[] args) { try (Socket socket = new Socket("localhost", 8080); Scanner scanner = new Scanner(System.in)){ System.out.println("已连接到服务端!"); OutputStream stream = socket.getOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(stream); System.out.println("请输入要发送给服务端的内容:"); String text = scanner.nextLine(); writer.write(text+'\n'); writer.flush(); System.out.println("数据已发送:"+text); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); System.out.println("收到服务器返回:"+reader.readLine()); }catch (IOException e){ System.out.println("服务端连接失败!"); e.printStackTrace(); }finally { System.out.println("客户端断开连接!"); } }
|
public static void main(String[] args) { try(ServerSocket server = new ServerSocket(8080)){ System.out.println("正在等待客户端连接..."); Socket socket = server.accept(); System.out.println("客户端已连接,IP地址为:"+socket.getInetAddress().getHostAddress()); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); System.out.print("接收到客户端数据:"); System.out.println(reader.readLine()); OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream()); writer.write("已收到!"); writer.flush(); }catch (IOException e){ e.printStackTrace(); } }
|
- 控制建立socket传输的时间限制
- 控制socket连接的通道
Socket传输文件
浏览器访问Web应用服务器
public static void main(String[] args) { try(ServerSocket server = new ServerSocket(8080)){ System.out.println("正在等待客户端连接..."); Socket socket = server.accept(); System.out.println("客户端已连接,IP地址为:"+socket.getInetAddress().getHostAddress()); InputStream in = socket.getInputStream(); System.out.println("接收到客户端数据:"); while (true){ int i = in.read(); if(i == -1) break; System.out.print((char) i); } }catch (Exception e){ e.printStackTrace(); } }
|
通过浏览器访问 http://localhost:8080或是http://127.0.0.1:8080/,来连接我们本地开放的服务器。
服务端却收到的信息:
GET / HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive Cache-Control: max-age=0 sec-ch-ua: "Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "macOS" Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,und;q=0.8,en;q=0.7
|
这些内容都是Http协议规定的请求头内容
如果需要给页面返回内容就必须包含如下的响应头:
具体的代码如下(注意看注释的部分):
public static void main(String[] args) { try(ServerSocket server = new ServerSocket(8080)){ System.out.println("正在等待客户端连接..."); Socket socket = server.accept(); System.out.println("客户端已连接,IP地址为:"+socket.getInetAddress().getHostAddress()); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); System.out.println("接收到客户端数据:"); while (reader.ready()) System.out.println(reader.readLine()); OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream()); writer.write("HTTP/1.1 200 Accepted\r\n"); writer.write("\r\n"); writer.write("lbwnb!"); writer.flush(); }catch (Exception e){ e.printStackTrace(); } }
|
此时可以用F12观察浏览器的响应过程