IP简介和分类:
IP(Internet Protocol) 网络互联协议,是一台计算机在网络上唯一识别。通常使用xxx.xxx.xxx.xxx格式表示,每个xxx用一个字节(1Byte=8bit)来表示,数字为0-255。
IP段分类:A类网 0-127 政府和大企业使用
127 有特殊用途 像 127.0.0.1代表本机
B类网 128-191 中小企业使用
C类网 192-223 个人或者团队使用
取值范围192.0.0.0 - 223.255.255.255
像我们使用192.168.2.64
D类网 224-239 广播使用(支持多播)
E类网 240-255 实验室使用
端口号简介和分类:
端口号(Port) 计算机逻辑通信端口。通俗的说,通过IP识别找到网络上某一台计算机,但是该计算机上存在多个网络应用程序,就需要使用端口号识别。通常使用2个字节(2^16=65536)表示端口号,取值范围就0-65535。
端口号分类:
公认端口(well known ports):取值范围从0-1023 紧密的绑定计算底层一些应用程序,建议自定义端口时不要使用。(ftp:21,ssh:22,http:80,https:443等等 )
注册端口 (registered ports): 取值范围从1024-49151,松散的绑定计算机一些应用程序,自定义端口号,建议使用这个范围之内(只要不冲突)。 (tomcat:8080,mysql:3306,oracle:1521,sqlserver:1433 等等)
动态/私有端口(dynamic/private ports): 取值范围从49152-65535,一些应用在使用过程中,需要动态的生成一些端口,就在该段产生。建议自定义端口时,不要使用。动态使用端口时,可以从1024,只要不冲突就可以。
3.2 TCP和UPD简介
网络7层协议:
物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。
要讲的TCP和UDP编程,属于传输层,本质就是使用该协议如何完成信息的传递。
TCP简介和区别:
TCP(Transimission Control Protocol) 传输控制协议,面向连接技术,可靠性高,消耗资源高,支持一对一,不支持广播。(类似QQ,微信的视频,音频等等)
UDP(User Datagram Protocol) 用户数据报协议,面试无连接技术,可靠性低,消耗资源低,支持一对一,支持广播。(类似QQ,微信的聊天功能)
TCP编程原理及实现(java语言)
原理:
服务端:
1)实例化一个 ServerSocket对象,绑定端口号。
2)调用accept方法,等待客户端连接(无客户端连入时会一直阻塞)。
3)使用输入流读客户端信息
4)使用输出流向客户端返回信息
5)关闭资源
客户端:
1) 实例化Socket对象,并指定主机(IP)和端口号。
2)使用输出流向服务端发送信息
3)使用输入流读服务端信息
4)关闭资源
实现:
测试时,都必须先启动服务端,再启动客户端。
1)简单对聊
服务端代码:
package com.aaa.tcp.demo1; import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { //ServerSocket 这个类实现了服务器套接字。 服务器套接字等待通过网络进入的请求。 它根据该请求执行一些操作,然后可能将结果返回给请求者。 ServerSocket serverSocket = null; Socket socket = null; InputStream inputStream = null; BufferedReader bufferedReader = null; OutputStream outputStream = null; PrintWriter printWriter = null; try { //1)实例化一个 ServerSocket对象,绑定端口号。 serverSocket = new ServerSocket(16868); //打印消息提示 System.out.println("服务器已经准备完毕,等待客户端连接。。。。。。"); //2)调用accept方法,等待客户端连接(无客户端连入时会一直阻塞)。 //accept() 侦听要连接到此套接字的客户端并接受它。 该方法将阻塞直到建立连接。 //Socket 该类实现客户端套接字(也称为“套接字”)。 套接字是两台机器之间通讯的端点。 socket = serverSocket.accept(); //3)使用输入流读客户端信息 inputStream = socket.getInputStream(); //把字节流转换为字符流使用InputStreamReader // 想使用按行读取,并且提高读取速度,建议使用BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String clientMsg = bufferedReader.readLine(); System.out.println("客户端说:"+clientMsg); //4)使用输出流向客户端返回信息 outputStream = socket.getOutputStream(); //想使用按行返回信息 printWriter = new PrintWriter(outputStream); //写回信息 printWriter.println("客户端你好,你发的信息"+clientMsg+"已经收到!"); //刷新管道 printWriter.flush(); } catch (IOException e) { e.printStackTrace(); } finally { //5)关闭资源 try { //先打开的后关闭 有套接关系,先关闭被套接的 if(outputStream!=null){ outputStream.close(); } if(printWriter!=null){ printWriter.close(); } if(inputStream!=null){ inputStream.close(); } if(bufferedReader!=null){ bufferedReader.close(); } if(socket!=null){ socket.close(); } if(serverSocket!=null){ serverSocket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
客户端代码:
package com.aaa.tcp.demo1; import java.io.*; import java.net.Socket; public class Client { public static void main(String[] args) { Socket socket = null; OutputStream outputStream = null; InputStream inputStream = null; PrintWriter printWriter = null; BufferedReader bufferedReader = null; try { //1) 实例化Socket对象,并指定主机(IP)和端口号。 socket = new Socket("对应IP",16868); //2)使用输出流向服务端发送信息 outputStream = socket.getOutputStream(); printWriter = new PrintWriter(outputStream); printWriter.println("你好,服务器!"); printWriter.flush(); //3)使用输入流读服务端信息 inputStream = socket.getInputStream(); bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String serverMsg = bufferedReader.readLine(); System.out.println("服务器说:"+serverMsg); } catch (IOException e) { e.printStackTrace(); } finally { //4)关闭资源 try { //先打开的后关闭 有套接关系,先关闭被套接的 if(inputStream!=null){ inputStream.close(); } if(bufferedReader!=null){ bufferedReader.close(); } if(outputStream!=null){ outputStream.close(); } if(printWriter!=null){ printWriter.close(); } if(socket!=null){ socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
2)控制台对聊
服务端代码:
package com.aaa.tcp.demo2; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; public class Server { public static void main(String[] args) { //ServerSocket 这个类实现了服务器套接字。 服务器套接字等待通过网络进入的请求。 它根据该请求执行一些操作,然后可能将结果返回给请求者。 ServerSocket serverSocket = null; Socket socket = null; InputStream inputStream = null; BufferedReader bufferedReader = null; OutputStream outputStream = null; PrintWriter printWriter = null; try { //1)实例化一个 ServerSocket对象,绑定端口号。 serverSocket = new ServerSocket(16666); //打印消息提示 System.out.println("服务器已经准备完毕,等待客户端连接。。。。。。"); //2)调用accept方法,等待客户端连接(无客户端连入时会一直阻塞)。 //accept() 侦听要连接到此套接字的客户端并接受它。 该方法将阻塞直到建立连接。 //Socket 该类实现客户端套接字(也称为“套接字”)。 套接字是两台机器之间通讯的端点。 socket = serverSocket.accept(); //3)使用输入流读客户端信息 inputStream = socket.getInputStream(); //把字节流转换为字符流使用InputStreamReader // 想使用按行读取,并且提高读取速度,建议使用BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); //4)使用输出流向客户端返回信息 outputStream = socket.getOutputStream(); //想使用按行返回信息 printWriter = new PrintWriter(outputStream); //使用Scanner类扫描控制台信息 Scanner scanner = new Scanner(System.in); //使用死循环一直接受和发送信息 while(true){ String clientMsg = bufferedReader.readLine(); System.out.println("客户端说:"+clientMsg); if(clientMsg.contains("借钱")){ //写回信息 printWriter.println("你被拉黑了!"); //刷新管道 printWriter.flush(); break; } //打印提示 System.out.println("请输入:"); String serverInputMsg = scanner.next(); //写回信息 printWriter.println(serverInputMsg); //刷新管道 printWriter.flush(); } } catch (IOException e) { e.printStackTrace(); } finally { //5)关闭资源 try { //先打开的后关闭 有套接关系,先关闭被套接的 if(outputStream!=null){ outputStream.close(); } if(printWriter!=null){ printWriter.close(); } if(inputStream!=null){ inputStream.close(); } if(bufferedReader!=null){ bufferedReader.close(); } if(socket!=null){ socket.close(); } if(serverSocket!=null){ serverSocket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
客户端代码:
package com.aaa.tcp.demo2; import java.io.*; import java.net.Socket; import java.util.Scanner; public class Client { public static void main(String[] args) { Socket socket = null; OutputStream outputStream = null; InputStream inputStream = null; PrintWriter printWriter = null; BufferedReader bufferedReader = null; try { //1) 实例化Socket对象,并指定主机(IP)和端口号。 socket = new Socket("对应IP",16666); //2)使用输出流向服务端发送信息 outputStream = socket.getOutputStream(); printWriter = new PrintWriter(outputStream); //3)使用输入流读服务端信息 inputStream = socket.getInputStream(); bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); //使用Scanner类扫描控制台信息 Scanner scanner = new Scanner(System.in); //使用死循环一直发送和接受信息 while(true) { //打印提示信息 System.out.println("请输入:"); String clientInputMsg = scanner.next(); printWriter.println(clientInputMsg); printWriter.flush(); String serverMsg = bufferedReader.readLine(); System.out.println("服务器说:" + serverMsg); if(serverMsg.contains("拉黑")){ printWriter.println("我想借钱"); printWriter.flush(); break; } } } catch (IOException e) { e.printStackTrace(); } finally { //4)关闭资源 try { //先打开的后关闭 有套接关系,先关闭被套接的 if(inputStream!=null){ inputStream.close(); } if(bufferedReader!=null){ bufferedReader.close(); } if(outputStream!=null){ outputStream.close(); } if(printWriter!=null){ printWriter.close(); } if(socket!=null){ socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
3)多线程对聊
服务端:
package com.aaa.tcp.demo3; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { ServerSocket serverSocket = null; try { //创建serverSocket服务端 serverSocket = new ServerSocket(16666); while(true){ System.out.println("服务端已经准备就绪,等待客户端连接。。。。"); //等待客户端连接 Socket socket = serverSocket.accept(); //如果有客户连入,直接启动一个线程 new Thread(new MTServer(socket)).start(); } } catch (IOException e) { e.printStackTrace(); } } }
多线程端:
package com.aaa.tcp.demo3; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; public class MTServer implements Runnable{ private Socket socket; /** * 通过构造方法,给socket赋值 * @param socket */ public MTServer(Socket socket) { this.socket = socket; } @Override public void run() { System.out.println("客户端"+Thread.currentThread().getName()+"已经连接,可以对话!!!!"); BufferedReader bufferedReader = null; PrintWriter printWriter = null; try { // (3) 连接建立后,通过输入流读取客户端发送的请求信息; //进行按行读取,提高效率,把字节流转换为字符流 //InputStreamReader 把字节流转字符流 BufferedReader在字符流套接缓存,提高读写效率 bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); // (4) 通过输出流向客户端发送相应信息; //可以通过字符流按行输出信息 printWriter = new PrintWriter(socket.getOutputStream()); //实例化Scanner类,调用next方法,接受控制台输入 Scanner scanner = new Scanner(System.in); while (true) { //按行读取客户端信息信息 String clientMsg = bufferedReader.readLine(); //打印 System.out.println("客户端说:" + clientMsg); //判断退出循环 if (clientMsg.contains("借钱")) { //写入信息 printWriter.println("你被拉黑了......"); //刷新管道 printWriter.flush(); break;//退出循环 } //打印提示 System.out.println("请输入:"); //阻塞并等待控制台输入 String serverInputMsg = scanner.next(); //写入信息 printWriter.println(serverInputMsg); //刷新管道 printWriter.flush(); } } catch (IOException e) { e.printStackTrace(); } finally { // (5) 关闭相应资源。 if (printWriter != null) { printWriter.close(); } try { if (bufferedReader != null) { bufferedReader.close(); } } catch (IOException e) { e.printStackTrace(); } try { if (socket != null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } /*public static void main(String[] args) { ServerSocket serverSocket = null; Socket socket = null; BufferedReader bufferedReader = null; PrintWriter printWriter = null; try { // (1) 创建ServerSocket对象,绑定监听端口; serverSocket = new ServerSocket(16666); System.out.println("服务端已准备就绪,等待客户端连接。。。。"); // (2) 通过accept()方法监听客户端请求(产生阻塞); socket = serverSocket.accept(); // (3) 连接建立后,通过输入流读取客户端发送的请求信息; //进行按行读取,提高效率,把字节流转换为字符流 //InputStreamReader 把字节流转字符流 BufferedReader在字符流套接缓存,提高读写效率 bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); // (4) 通过输出流向客户端发送相应信息; //可以通过字符流按行输出信息 printWriter = new PrintWriter(socket.getOutputStream()); //实例化Scanner类,调用next方法,接受控制台输入 Scanner scanner =new Scanner(System.in); while(true) { //按行读取客户端信息信息 String clientMsg = bufferedReader.readLine(); //打印 System.out.println("客户端说:" + clientMsg); //判断退出循环 if(clientMsg.contains("借钱")){ //写入信息 printWriter.println("你被拉黑了......"); //刷新管道 printWriter.flush(); break;//退出循环 } //打印提示 System.out.println("请输入:"); //阻塞并等待控制台输入 String serverInputMsg = scanner.next(); //写入信息 printWriter.println(serverInputMsg); //刷新管道 printWriter.flush(); } } catch (IOException e) { e.printStackTrace(); } finally { // (5) 关闭相应资源。 if(printWriter!=null){ printWriter.close(); } try { if(bufferedReader!=null){ bufferedReader.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(socket!=null){ socket.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(serverSocket!=null){ serverSocket.close(); } } catch (IOException e) { e.printStackTrace(); } } }*/ }
客户端:
package com.aaa.tcp.demo3; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; public class Client { public static void main(String[] args) { Socket socket = null; PrintWriter printWriter = null; BufferedReader bufferedReader = null; try { // (1) 创建Socket对象,指明需要连接的服务器地址和端口; socket = new Socket("对应IP",16666); // (2) 连接建立后,通过输出流向服务器端发送请求信息; printWriter = new PrintWriter(socket.getOutputStream()); // (3) 通过输入流获取服务器端返回的响应信息; bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); //实例化Scanner类,调用next方法,接受控制台输入 Scanner scanner =new Scanner(System.in); while(true) { System.out.println("请输入:"); String clientInputMsg = scanner.next(); //写入消息 printWriter.println(clientInputMsg); //刷新管道 printWriter.flush(); //按行读取信息 String serverMsg = bufferedReader.readLine(); //打印 System.out.println("服务器说:" + serverMsg); //判断退出循环 if(serverMsg.contains("拉黑")){ //写入信息 printWriter.println("别慌,拉黑前借钱"); //刷新管道 printWriter.flush(); break;//退出循环 } } } catch (IOException e) { e.printStackTrace(); } finally { // (4) 关闭相应资源。 try { if(bufferedReader!=null){ bufferedReader.close(); } } catch (IOException e) { e.printStackTrace(); } if(printWriter!=null){ printWriter.close(); } try { if(socket!=null){ socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
3.4 UDP编程原理及实现(java语言)
原理:
服务端(发送):
1)实例化发送/接受对象
2) 准备发送信息
3)使用发送信息,封装数据报包对象
4)发送
客户端(接送):
1)实例化发送/接受对象
2)准备接受容器(缓存)
3)使用接受容器封装数据报包对象
4)接受并拼装数据
实现:
1)简单信息发送和接受
先启动客户端,再启动服务端
服务端:
package com.aaa.udp.demo1; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; public class Server { public static void main(String[] args) { try ( //jdk7 语法,可以把需要关闭的资源放到try()中,使用后回自动关闭,不用手动关闭 // 1)实例化发送/接受对象 //DatagramSocket 此类表示用于发送和接收数据报数据包的套接字。 DatagramSocket datagramSocket = new DatagramSocket(); ){ // 2) 准备发送信息 String sendMessage = "hello qy153!"; //转为字节数组 byte[] sendMessageBytes = sendMessage.getBytes(); // 3)使用发送信息,封装数据报包对象 // DatagramPacket该类表示数据报包。数据报包用于实现无连接分组传送服务。 仅基于该数据包中包含的信息,每个消息从一台机器路由到另一台机器。 DatagramPacket datagramPacket = new DatagramPacket(sendMessageBytes,sendMessageBytes.length, InetAddress.getByName("对应IP"),18888); // 4)发送 datagramSocket.send(datagramPacket); //打印提示 System.out.println("发送完毕!!"); } catch (Exception e) { e.printStackTrace(); } } }
客户端:
package com.aaa.udp.demo1; import java.net.DatagramPacket; import java.net.DatagramSocket; public class Client { public static void main(String[] args) { try( //1)实例化发送/接受对象 // 构造数据报套接字并将其绑定到本地主机上的指定端口。 DatagramSocket datagramSocket =new DatagramSocket(18888); ){ //2)准备接受容器(缓存) ['h','e','l'.....'!'] byte[] receiveMsgByte = new byte[2048]; //3)使用接受容器封装数据报包对象 DatagramPacket datagramPacket = new DatagramPacket(receiveMsgByte,2048); //打印提示信息 System.out.println("客户端准备完毕,等待服务端发送消息。。。。。"); //4)接受并拼装数据 // receive() 从此套接字接收数据报包。当此方法返回时, DatagramPacket的缓冲区将填充接收到的数据。 // 该方法阻塞,直到接收到数据报。 datagramSocket.receive(datagramPacket); //拼装并打印接受到的信息 datagramPacket 数据包报,会记录当前接受方法,接受到的字节长度 String receiveMsg = new String(receiveMsgByte,0,datagramPacket.getLength()); System.out.println("接受到的信息为:"+receiveMsg); } catch (Exception e) { e.printStackTrace(); } } }
3) UDP对聊
服务端:
package com.aaa.udp.demo2; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.Scanner; public class Server { public static void main(String[] args) { DatagramSocket datagramSocket = null; try { // 1) 创建服务端 DatagramSocket 类 + 指定的发送端口 datagramSocket = new DatagramSocket(7777); //实例化Scanner Scanner scanner = new Scanner(System.in); while (true){ System.out.println("请输入:"); // 2) 准备数据 以字节数组的形式 String sendMsg = scanner.next(); //String sendMsg = "您好,客户端,我是服务器端,测试数据发送。。。"; byte[] sendMsgByte = sendMsg.getBytes("UTF-8"); // 3) 打包 DatagramPacket+客户端的地址和端口 DatagramPacket datagramPacket = new DatagramPacket(sendMsgByte,sendMsgByte.length, InetAddress.getByName("localhost"),8888); // 4) 发送 datagramSocket.send(datagramPacket); System.out.println("数据发送完毕。。。。。。。。。。。"); //定义一个字节数组,作为缓冲容器,接受 byte[] receiveBytes = new byte[2048]; DatagramPacket datagramPacketServer = new DatagramPacket(receiveBytes, 2048); // 3) 包 接收数据 并记录接受数据的长度 长度由datagramPacket记录 System.out.println("客户端准备完毕,等待服务端发送数据:"); datagramSocket.receive(datagramPacketServer); // 4) 分析 (组装字节数组) String receiveStr = new String(receiveBytes, 0, datagramPacket.getLength()); System.out.println("接受的数据为:" + receiveStr); if(receiveStr.contains("88")){ break; } } System.out.println("服务器端退出。。。。"); } catch (Exception e) { e.printStackTrace(); } finally { // 5) 释放资源 if(datagramSocket!=null){ datagramSocket.close(); } } } }
客户端:
package com.aaa.udp.demo2; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.Scanner; public class Client { public static void main(String[] args) { DatagramSocket datagramSocket = null; try { // 1) 创建客户端 DatagramSocket 类 + 指定的接收端口 datagramSocket = new DatagramSocket(8888); //实例化Scanner Scanner scanner = new Scanner(System.in); // 2) 准备接收数据的容器 以字节数组的形式封装为DatagramPacket while (true) { //定义一个字节数组,作为缓冲容器,接受 byte[] receiveBytes = new byte[2048]; DatagramPacket datagramPacket = new DatagramPacket(receiveBytes, 2048); // 3) 包 接收数据 并记录接受数据的长度 长度由datagramPacket记录 System.out.println("客户端准备完毕,等待服务端发送数据:"); datagramSocket.receive(datagramPacket); // 4) 分析 (组装字节数组) String receiveStr = new String(receiveBytes, 0, datagramPacket.getLength()); System.out.println("接受的数据为:" + receiveStr); if(receiveStr.contains("88")){ String sendMsg = "88"; //String sendMsg = "您好,客户端,我是服务器端,测试数据发送。。。"; byte[] sendMsgByte = sendMsg.getBytes("UTF-8"); // 3) 打包 DatagramPacket+客户端的地址和端口 DatagramPacket datagramPacketClient = new DatagramPacket(sendMsgByte,sendMsgByte.length, InetAddress.getByName("localhost"),7777); // 4) 发送 datagramSocket.send(datagramPacketClient); break; } System.out.println("请输入:"); // 2) 准备数据 以字节数组的形式 String sendMsg = scanner.next(); //String sendMsg = "您好,客户端,我是服务器端,测试数据发送。。。"; byte[] sendMsgByte = sendMsg.getBytes("UTF-8"); // 3) 打包 DatagramPacket+客户端的地址和端口 DatagramPacket datagramPacketClient = new DatagramPacket(sendMsgByte,sendMsgByte.length, InetAddress.getByName("localhost"),7777); // 4) 发送 datagramSocket.send(datagramPacketClient); System.out.println("数据发送完毕。。。。。。。。。。。"); } System.out.println("客户端端退出。。。。"); } catch (Exception e) { e.printStackTrace(); } finally { // 5) 释放资源 if(datagramSocket!=null){ datagramSocket.close(); } } } }