网络编程
1.1 概述
计算机网络是指将位置不同的多台[计算机 通过通信线路连接起来,实现资源共享和信息传递的计算机系统
1.2 网络通信的要素
- ip和端口
- 网络通信协议(tcp/udp)
1.3 Ip地址(Internet Protocol)
-
定位唯一一台计算机
-
127.0.0.0:本机 localhost
-
ip地址的分类(ip4/ip6)
-
ip4 四个字节组成 2011年用尽
-
Ip6 通常写成8组,每组为四个十六进制数的形式 非常多,基本用不完
CDCD:910A:2222:5498:8475:1111:3900:2020 1030::C9B4:FF12:48AA:1A2B 2000:0:0:0:0:0:0:1
-
公网(互联网)/私网(局域网)
- 192.168.xx.xx 这种类型的代表的就是私网
- 其它类型 a.b.c.d 代表公网
-
域名:ip不方便记忆 不能显示地址组织的名称和性质,人们设计出了域名,通过DNS将域名和Ip关联,方便访问
-
1.4 端口(port)
端口:计算机与外界通讯交流的出口
- 代表计算机上的某一个程序的进程
- 不同的进程有不同的端口,代表不同的程序
- 被规定0-65535中间
- TCP UDP,单个协议下,端口互不冲突
- 端口分类
- 公有端口 从0到1023
- http:8080
- ftp:21
- https:443
- 程序注册端口1024~49151,分配给用户或程序
- tomcat:8080
- Mysql:3306
- Oracle:1521
- 动态和/或私有端口 49152~65535
- 公有端口 从0到1023
1.5 通信协议
通信协议:双方必须遵循的规则和约定。 确保网络中数据顺利地传送到确定的地方。
常见协议:
-
tcp/ip协议:传输控制协议/Internet协议,TCP/IP是由一组具有专业用途的多个子协议组合而成的,这些子协议包括TCP、IP、UDP、ARP、ICMP等
-
tcp协议:打电话
-
一种面向连接的、可靠的、基于字节流的传输层通信协议
-
连接稳定(一定会发送成功)
- 连接 三次握手
- 断开 四次挥手
-
分客户端、服务端
-
传输完成,断开连接,效率低
-
接收消息代码
public static void main(String[] args) { try { //等待 接收消息 ServerSocket serverSocket = new ServerSocket(1025); //等待服务连接 Socket socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); Scanner scanner = new Scanner(inputStream); while (scanner.hasNext()){ System.out.print(scanner.next()); } inputStream.close(); socket.close(); serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } }
-
发送消息必须是服务端开启才能发送,否则
java.net.ConnectException: Connection refused: connect at java.net.DualStackPlainSocketImpl.connect0(Native Method) at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at java.net.Socket.connect(Socket.java:538) at java.net.Socket.<init>(Socket.java:434) at java.net.Socket.<init>(Socket.java:244) at tcpDemo.TcpClientDemo1.main(TcpClientDemo1.java:12) Process finished with exit code 0
- 发送消息代码
public static void main(String[] args) { try { //发送消息 InetAddress inetAddress = InetAddress.getByName("localhost"); Socket socket = new Socket(inetAddress, 1025); OutputStream outputStream = socket.getOutputStream(); outputStream.write("helloTcp".getBytes()); } catch (Exception e) { e.printStackTrace(); } }
-
使用FTP实现文件上传
- 服务器代码(开启服务 等待上传)
public static void main(String[] args) throws Exception { //创建服务 ServerSocket serverSocket = new ServerSocket(1026); //监听客户端连接 Socket socket = serverSocket.accept(); //获取输入流 InputStream is = socket.getInputStream(); //输出文件 FileOutputStream fos = new FileOutputStream(new File("2.jpg")); byte[] buffer = new byte[1024]; int len ; while ((len=is.read(buffer))!=-1){ fos.write(buffer,0,len); } //告诉客户端接收到了文件 OutputStream os = socket.getOutputStream(); os.write("服务端收到了文件".getBytes()); //关闭资源 os.close(); fos.close(); is.close(); socket.close(); serverSocket.close(); }
-客户端代码(上传文件,服务开启时才能上传成功)
public static void main(String[] args) throws Exception { //创建连接 Socket socket = new Socket("localhost",1026); //获取输出流 OutputStream outputStream = socket.getOutputStream(); //读取文件 FileInputStream fis=new FileInputStream(new File("1.jpg")); byte[] buffer =new byte[1024]; int len; while ((len=fis.read(buffer))!=-1){ outputStream.write(buffer,0,len); } //通知服务器 已经传输完毕 socket.shutdownOutput(); //文件发送完毕,接收服务端返回消息 InputStream is = socket.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer2 = new byte[1024] ; int len2; while ((len2=is.read(buffer2))!=-1){ baos.write(buffer2,0,len2); } System.out.println("客户端: "+baos.toString()); //关闭资源 fis.close(); outputStream.close(); socket.close(); }
-
-
UDP协议:发短信
-
不连接 不稳定(消息可能发送失败)
-
客户端 服务端 不明确
-
UDP实现消息发送
- 发送方代码(无论是否有人接收,都能发送成功)
public static void main(String[] args) throws Exception{ DatagramSocket socket = new DatagramSocket(2222); while (true){ BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String readLine = reader.readLine(); DatagramPacket packet = new DatagramPacket(readLine.getBytes(),0,readLine.getBytes().length,new InetSocketAddress("localhost",2233)); socket.send(packet); if(readLine.equals("bye")){ break; } } socket.close(); }
- 接收方代码
public static void main(String[] args) throws Exception{ DatagramSocket socket = new DatagramSocket(2233); while (true){ byte[] buffer = new byte[1024]; DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length); socket.receive(datagramPacket); byte[] data = datagramPacket.getData(); String receiveStr = new String(data,0,data.length).trim(); System.out.println(receiveStr); if(receiveStr.equals("bye")){ break; } } socket.close(); }
-
实现聊天
- 接收方
package udpDemo; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class TaskReveive implements Runnable{ private int reveivePort; private DatagramSocket socket; public TaskReveive(int reveivePort) { this.reveivePort = reveivePort; try { socket = new DatagramSocket(reveivePort); } catch (SocketException e) { e.printStackTrace(); } } @Override public void run() { while (true){ try { byte[] buffer = new byte[1024]; DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length); socket.receive(datagramPacket); byte[] data = datagramPacket.getData(); String receiveStr = new String(data,0,data.length).trim(); System.out.println(receiveStr); if(receiveStr.equals("bye")){ break; } }catch (Exception e){ e.printStackTrace(); } } socket.close(); } }
- 发送方
package udpDemo; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; public class TaskSender implements Runnable{ private int sendPort; private String sendIp; private int myPort; private String myIP; public TaskSender(int sendPort, String sendIp, int myPort, String myIP) { this.sendPort = sendPort; this.sendIp = sendIp; this.myPort = myPort; this.myIP = myIP; } @Override public void run(){ try { DatagramSocket socket = new DatagramSocket(myPort); while (true){ BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String readLine = reader.readLine(); InetSocketAddress inetSocketAddress = new InetSocketAddress(sendIp, sendPort); DatagramPacket packet = new DatagramPacket(readLine.getBytes(),0,readLine.getBytes().length,inetSocketAddress); socket.send(packet); if(readLine.equals("bye")){ break; } } socket.close(); }catch (Exception e){ e.printStackTrace(); } } }
- 每人一个接收消息 一个发送消息 实现通信
package udpDemo; public class TaskStudent { public static void main(String[] args) { new Thread(new TaskSender(2233, "localhost", 2244, "localhost")).start(); new Thread(new TaskReveive(3322)).start(); } }
package udpDemo; public class TestTeacher { public static void main(String[] args) { new Thread(new TaskSender(3322, "localhost", 3323,"localhost")).start(); new Thread(new TaskReveive(2233)).start(); } }
-
1.6 面试题
-
说一下HTTP协议
HTTP协议:超文本传输协议,属于应用层协议,规定了客户端与服务端传输数据的格式;它是无状态的,对于前面传送过的信息没有记录;请求方式有GET,POST,HEAD,PUT,DELETE等等。
最主要的get,post方法;
-
get请求:数据会以URL的形式传输,对数据大小有一定的限制,安全性比较低 ,用于传输一些比较小,安全性要求低的数据;
-
post请求:数据是通过数据包的形式传输,比较安全,用于传输比较大的,对于安全性要求较高的数据;
HTTP转态码: 状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:
1xx:指示信息--表示请求已接收,继续处理 2xx:成功--表示请求已被成功接收、理解、接受 200 OK //客户端请求成功 3xx:重定向--要完成请求必须进行更进一步的操作 4xx:客户端错误--请求有语法错误或请求无法实现 400 Bad Request //客户端请求有语法错误,不能被服务器所理解 401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用 403 Forbidden //服务器收到请求,但是拒绝提供服务 404 Not Found //请求资源不存在,eg:输入了错误的URL 5xx:服务器端错误--服务器未能实现合法的请求 500 Internal Server Error //服务器发生不可预期的错误 503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
-
-
Tcp/Udp的区别
- 基于连接与无连接
- TCP要求系统资源较多,UDP较少; (原因是tcp需要保持连接,udp不需要)
- UDP程序结构较简单
- 流模式(TCP)与数据报模式(UDP);
- TCP保证数据正确性,UDP可能丢包 (原因是tcp连接时发送 ,udp无连接,接收方无连接时可能会丢包)
- TCP保证数据顺序,UDP不保证
- tcp建立连接和断开连接
-
建立连接(三次握手) 双方都确认准备完毕开始发送
- 主机A向主机B发出连接请求数据包:“我想给你发数据,可以吗?”这是第一次对话
- 主机B向主机A发送同意连接和要求同步:可以,你什么时候发?”
- 主机A再发出一个数据包确认主机B的要求同步:“我现在就发,你接着吧!”
三次“对话”的目的是使数据包的发送和接收同步,经过三次“对话”之后,主机A才向主机B正式发送数据。
-
断开连接(四次挥手)
- 关闭方(可以是客户端也可以是服务端)发送一个包,表示自己没有要发送的数据了,这个时候开始等待被关闭方返回的消息
-
被关闭方接收到了关闭方发送的报文以后,也会发送数据包,告诉关闭方,他收到了关闭方发送的关闭连接的请求,但是这个时候,服务端可能还有没有发送的数据,这个时候可以发送数据。
- 被关闭方告诉关闭方,它数据发送完成,它也要关闭了
-
关闭方,告诉被关闭方,它知道了。
-
为什么要4次挥手?
-
确保数据能够完整传输。
-
当被动方收到主动方的FIN报文通知时,它仅仅表示主动方没有数据再发送给被动方了。
-
但未必被动方所有的数据都完整的发送给了主动方,所以被动方不会马上关闭SOCKET,它可能还需要发送一些数据给主动方后,
-
再发送FIN报文给主动方,告诉主动方同意关闭连接,所以这里的ACK报文和FIN报文多数情况下都是分开发送的。
-