一、网络分层协议: -OSI 七层协议 -TCP/IP 四(五)层协议 1.数据传输过程的5要素:(1)目标地址IP (2)目标端口 (3)源地址IP (4)源端口号 (5)协议类型 2、传输层:TCP/UDP UDP:无连接,不稳定,面向数据报 Datagram TCP(主流):有连接,稳定,面向数据流(应用层协议中的HTTP协议就是基于TCP/IP协议实现的) 3.数据传输过程(封装、分用) 封装:从应用层到物理层的过程 分用:从物理层到应用层的过程 二、网络中的地址管理 1、IP(IPV4/IPV6) (1)查看本机的IP:cmd -> ipconfig IPV4:32位数值(0/1)组成 2.MAC:物理地址、网卡地址 cmd -> ipconfig /all 三、UDP编程 例:智能机器人
public class UDPServer {
private static final int port = 9001;
private static final int bleng = 1024;
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(port);
System.out.println("服务器端已启动");
while (true) {
DatagramPacket client = new DatagramPacket(
new byte[bleng],
bleng
);
socket.receive(client);
String msg = new String(client.getData());
System.out.println("接受客户端的消息:"+msg);
String str = msg.replace("吗?",".");
DatagramPacket serMsg = new DatagramPacket(
str.getBytes(),
str.getBytes().length,
client.getAddress(),
client.getPort()
);
socket.send(serMsg);
}
}
}
public class UDPClient {
private static final int port = 9001;
private static String ip = "127.0.0.1";
private static final int bleng = 1024;
public static void main(String[] args) throws IOException {
DatagramSocket client = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("我:");
String msg = sc.nextLine();
DatagramPacket clientMsg = new DatagramPacket(
msg.getBytes(),
msg.getBytes().length,
InetAddress.getByName(ip),
port
);
client.send(clientMsg);
DatagramPacket socketMsg = new DatagramPacket(
new byte[bleng],
bleng
);
client.receive(socketMsg);
String str = new String(socketMsg.getData());
System.out.println("对方:"+str);
}
}
}
四、将项目发布到服务器上 例:UDP服务器发布: 1、 2、build artifacts 3、在Xftp中引入jar包,在xshell中使用命令:java -jar xxx.jar 五、TCP编程
public class TCPServer {
private static final int port = 9002;
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("服务器端已启动");
Socket clientSocket = serverSocket.accept();
System.out.println(String.format("已有客户端的链接,IP:%s,端口号:%d",
clientSocket.getInetAddress().getHostAddress(),clientSocket.getPort()));
try(
BufferedReader reader = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(clientSocket.getOutputStream()))
) {
while (true) {
String msg = reader.readLine();
System.out.println("接收到客户端的消息:" + msg);
String serMsg = "我收到了";
writer.write(serMsg + "\n");
writer.flush();
}
}
}
}
public class TCPClient {
private static final String ip = "127.0.0.1";
private static final int port = 9002;
public static void main(String[] args) throws IOException {
Socket socket = new Socket(ip,port);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Scanner sc = new Scanner(System.in)
){
while (true) {
System.out.println("->");
String msg = sc.nextLine();
writer.write(msg+"\n");
writer.flush();
String serMsg = reader.readLine();
if (serMsg != null) {
System.out.println("服务器端返回:" + serMsg);
}
}
}
}
}
六、HTTP协议 实现HTTP服务器的关键是:遵循HTTP协议 request:1.首行(方法类型 URI HTTP版本号) 2.head 3.空行 4.body response:1.首行(HTTP版本号 状态码 状态描述符) 2.head(Content-type:text/html Content-Length) 3.空行 4.返回信息
public class MyHttp {
private static final int port = 9004;
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("服务器端已启动~");
Socket socket = serverSocket.accept();
try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))
) {
String firstLine = reader.readLine();
String[] firstLineArr = firstLine.split(" ");
String method = firstLineArr[0];
String uri = firstLineArr[1];
String httpVersion = firstLineArr[2];
System.out.println(String.format("首行信息 -> 方法类型:%s,uri:%s,HTTP版本号:%s",
method,uri,httpVersion));
String content = "";
if (uri.contains("404")) {
content = "<h1>没有找到此页面</h1>";
} else if (uri.contains("200")) {
content = "<h1>你好,世界</h1>";
}
writer.write(String.format("首行信息 -> HTTP版本号:%s,200,ok",httpVersion+"\n"));
writer.write("Content-type: text/html;charset=utf-8\n");
writer.write("Content-Length: "+content.getBytes().length+"\n");
writer.write("\n");
writer.write(content);
writer.flush();
}
}
}
七、TCP/IP 1.传输层: (1)端口号:找到应用程序 最大端口号:0-65535 端口号分类: 知名端口号 0-1023(FTP:21,SSH:22,Telnet:23,HTTP:80,HTTPS:443,MySQL:3306,tomcat:8080) 动态端口号:1024-65535 八、TCP特性 1.确认应答(ACK)机制(保障 TCP 稳定的核心机制) 2.超时重传机制 超时重发的策略: 策略1:发送不会以固定的频率发送。策略1采取的是悲观策略,如果第一次发送消息失败了,那么大概率第二次也会失败,所以TCP会以指数级超时时间增长的频率去发送消息。 策略2:如果经历了一定的重试次数,消息还没有得到应答,就会停止发送。 3.连接管理机制 3次握手(3次通讯) 4次挥手(4次通讯) ESTABLISHED:表示3次握手已经完成,可以进行数据的传输了。 服务器端先变为CLOSED状态,客户端的TIME_WAIT会等待 2 MSL(最大超时时间)状态才会变为CLOSED。 2 MSL = ACK 最大超时时间(1 MSL) + 对方发送给它消息的一个最大等待时间(1 MSL)。 4.滑动窗口 一发一收的方式性能较低, 那么我们一次发送多条数据, 就可以大大的提高性能。 如果出现了丢包, 如何进行重传? 这里分两种情况讨论. 情况一: 数据包已经抵达, ACK被丢了。 这种情况下, 部分ACK丢了并不要紧, 因为可以通过后续的ACK进行确认。 ACK=6000 的含义:告诉主机A,我成功的收到了 0~6001 ACK返回的值是当前(主机B_右边)接收缓冲区的下一个值(最大连续值) 情况二: 数据包就直接丢了。 当前面的数据被正常补齐之后,返回的ACK是最大值,这种机制叫做“快重传”。 面试问题 1.TCP,UDP的区别: UDP:无连接,不稳定,面向数据报 ; 没有发送缓冲区,只有接收缓冲区。 TCP:有连接,稳定,面向数据流; 既有发送缓冲区,又有接收缓冲区。 2.UDP 一个包的最大理论长度=2的16次方 = 65536/1024=64KB,如果 UDP 编程的时候的数据大小大于64KB会怎摸样? (1)在 应用层进行数据包的拆分和组合。 (2)大于64KB不用处理,交给TCP/IP协议去处理,它会在网络层进行分包和组包(缺点:一个包丢失整组包舍弃)。 3.两次握手可不可以? 不可以,不能证明客户端的接受能力和服务器端的发送能力。 4.三次挥手可以吗? 有可能可以。 对应到程序:接收缓冲区没有数据了,那么就可以直接关闭连接。 5.如果发现服务器端存在大量的CLOSED_WAIT 说明程序有问题? 服务器没有正确的关闭 socket, 导致四次挥手没有正确完成. 这是一个 BUG. 只需要加上对应的 close 即可解决问题
|