网络编程

image.png
端口号是用两个字节(16位的二进制数)表示的,它的取值范围是0~65535,其中,0~1023之间的端口号用于一些知名的网络服务和应用,用户的普通应用程序需要使用1024以上的端口号,从而避免端口号被另外一个应用或服务所占用。

  1. package com.igeek_01;
  2. /**
  3. * @author Lynn
  4. * @create 2020-12-16-10:20
  5. */
  6. import java.net.InetAddress;
  7. import java.net.UnknownHostException;
  8. /**
  9. * 凡是.net包下的内容都是关于网络的api
  10. */
  11. public class IPDemo {
  12. public static void main(String[] args) throws UnknownHostException {
  13. //获取本地IP地址
  14. InetAddress localhost=InetAddress.getLocalHost();
  15. System.out.println(localhost);//Lynn/192.168.2.184
  16. //获取字符串类型的IP
  17. String hostname=localhost.getHostName();
  18. System.out.println(hostname);//Lynn
  19. String hostAddress=localhost.getHostAddress();
  20. System.out.println(hostAddress);//192.168.2.184
  21. //获取其他IP地址
  22. InetAddress byName=InetAddress.getByName("Lynn");
  23. System.out.println(byName);//Lynn/192.168.2.184
  24. }
  25. }

UDP

image.png
发送和接收均可以使用的Socket类:

  1. DatagramSocket

  • 数据打包的相关类:

    1. DatagramPacket

  • 使用UDP接收数据的步骤:
    1. 1、建立接收端;
    1. public DatagramSocket(int port): 指定程序端口号,方便发送端寻找
    1. 2、建立数据包,用于接收数据;
    1. public DatagramPacket(byte[] buf, int length)
    1. 3、调用Socket的接收方法;
    1. 4、解析数据
    1. public byte[] getData(): 获取数据报包中的数据
    1. public int getLength(): 获取数据报包中的数据长度
    1. public InetAddress getAddress(): 获取发送方的IP
    1. public int getPort(): 获取发送方的端口号
    1. 5、关闭Socket

    案例1

    ```java package com.igeek_02;

import java.io.IOException; import java.net.*;

/**

  • UDP是一个传输协议 *
  • 当前的服务器端用于接收数据 */ public class UDPService { public static void main(String[] args) throws IOException {

    1. //建立连接
    2. DatagramSocket ds=new DatagramSocket(123);
    3. //建立数据包,用于接收数据
    4. byte[] bytes=new byte[1024];
    5. DatagramPacket dp=new DatagramPacket(bytes, bytes.length);
    6. //调用socket方法接收数据
    7. ds.receive(dp);
    8. //解析数据--针对数据包进行解析
    9. InetAddress sendAddress=dp.getAddress();
    10. String sendIP=sendAddress.getHostAddress();
    11. int sendPort=dp.getPort();//端口号
    12. //获取数据包中的数据
    13. byte[] data=dp.getData();
    14. int length=dp.getLength();
    15. //将字节数组转换成字符串--String的构造函数
    16. String s = new String(data, 0, length);
    17. //输出
    18. System.out.println("接收到来自"+sendIP+"的,端口号为"+sendPort+"的数据"+ s);
    19. //关闭
    20. ds.close();

    } } java package com.igeek_02;

/**

  • @author Lynn
  • @create 2020-12-16-11:21 */

import java.net.*;

/**

  • 发送端 */ public class UDPSend { public static void main(String[] args) throws Exception, UnknownHostException {

    1. //建立连接
    2. DatagramSocket ds=new DatagramSocket();
    3. //创建数据
    4. String s="I Love Java";
    5. //数据打包
    6. byte[] data=s.getBytes();//将字符串转化为字节数组
    7. int length= data.length;
    8. InetAddress address=InetAddress.getByName("192.168.2.184");
    9. int port=123;//必须与接收端的一致
    10. DatagramPacket dp=new DatagramPacket(data,length,address,port);
    11. //调用方法进行发送
    12. ds.send(dp);
    13. //关闭连接
    14. ds.close();

    } } ```

    案例2

    ```java package com.igeek_03;

import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress;

/**

  • UDP是一个传输协议 *
  • 当前的服务器端用于循环接收数据 */ public class UDPService { public static void main(String[] args) throws IOException {

    1. //建立连接
    2. DatagramSocket ds=new DatagramSocket(123);
    3. //反复接收数据
    4. while (true){
    5. //建立数据包,用于接收数据
    6. byte[] bytes=new byte[1024];
    7. DatagramPacket dp=new DatagramPacket(bytes, bytes.length);
    8. //调用socket方法接收数据
    9. ds.receive(dp);
    10. //解析数据--针对数据包进行解析
    11. InetAddress sendAddress=dp.getAddress();
    12. String sendIP=sendAddress.getHostAddress();
    13. int sendPort=dp.getPort();//端口号
    14. //获取数据包中的数据
    15. byte[] data=dp.getData();
    16. int length=dp.getLength();
    17. //将字节数组转换成字符串--String的构造函数
    18. String s = new String(data, 0, length);
    19. //输出
    20. System.out.println("接收到来自"+sendIP+"的,端口号为"+sendPort+"的数据:"+ s);
    21. }
    22. /*//关闭
    23. ds.close();*/

    } } java package com.igeek_03;

/**

  • @author Lynn
  • @create 2020-12-16-11:21 */

import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Scanner;

/**

  • 发送端 */ public class UDPSend { public static void main(String[] args) throws Exception, UnknownHostException {

    1. //建立连接
    2. DatagramSocket ds=new DatagramSocket();
    3. //循环发送
    4. while (true){
    5. //创建数据--灵活的数据
    6. Scanner sc=new Scanner(System.in);
    7. System.out.println("请输入数据:");
    8. String s=sc.next();
    9. //数据打包
    10. byte[] data=s.getBytes();//将字符串转化为字节数组
    11. int length= data.length;
    12. InetAddress address=InetAddress.getByName("192.168.2.184");
    13. int port=123;//必须与接收端的一致
    14. DatagramPacket dp=new DatagramPacket(data,length,address,port);
    15. //调用方法进行发送
    16. ds.send(dp);
    17. /*//关闭连接
    18. ds.close();*/
    19. }

    } } ```

    练习

    ```java package Test01;

/**

  • @author Lynn
  • @create 2020-12-16-20:19 */

import java.io.IOException; import java.net.*; import java.util.Scanner;

/**

  • 一、 项目需求:请用户完成一个UDP接收端作为模拟网络聊天室的操作。
  • 1:创建UDP传输下的聊天室发送端UDPSend类
  • 2: 创建UDP传输下的聊天室接收端 Room类
  • 1.2. 操作步骤描述
    1. 建立项目目录:day14作业_Test2_1
    1. 创建UDPSend类,并包含main()方法;
  • 在该main方法中
  • a、建立UDP的Socket服务;
  • b、将要发送的数据封装到数据包中;
  • c、通过UDP的Socket服务将数据包发送出去;
  • d、关闭Socket服务
    1. 创建Room类 使用UDP接收端实现网络聊天效果
  • 该类中写main方法 步骤如下
  • a、建立UDP的Socket服务,因为要接收数据,所以必须明确一个端口号;
  • 添加while(ture)循环,不断的循环接收内容
  • b、创建数据包,用于存储接收到的数据,方便用数据包对象的方法解析这些数据;
  • c、使用UDP的Socket服务的receive方法接收数据并存储到数据包中;
  • d、通过数据包的方法解析这些数据; */ public class UDPSend { public static void main(String[] args) throws IOException { //建立UDP的Socket服务 DatagramSocket datagramSocket=new DatagramSocket();

    //将数据存放到数据包 //循环发送 while (true){ Scanner sc=new Scanner(System.in); System.out.println(“请输入数据:”); String s=sc.next();

    //打包数据 byte[] bytes=s.getBytes();//将字符串转换为字节数组 int length= bytes.length; InetAddress inetAddress=InetAddress.getByName(“192.168.2.184”); int port=8888; DatagramPacket dp=new DatagramPacket(bytes,length,inetAddress,port);

    //发送 datagramSocket.send(dp);

    ///关闭服务 datagramSocket.close();/ }

    } } java package Test01;

import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException;

/**

  • @author Lynn
  • @create 2020-12-16-20:38 */ public class Room { public static void main(String[] args) throws IOException {

    1. //建立连接
    2. DatagramSocket ds=new DatagramSocket(8888);
    3. //不断循环接收数据
    4. while (true){
    5. //创建数据包接收数据
    6. byte[] bytes=new byte[1024];
    7. DatagramPacket dp=new DatagramPacket(bytes, bytes.length);
    8. //接收数据包
    9. ds.receive(dp);
    10. //解析数据
    11. InetAddress sendAddress=dp.getAddress();
    12. String sendIP= sendAddress.getHostAddress();
    13. int port=dp.getPort();
    14. //存入
    15. byte[] data=dp.getData();
    16. int length= dp.getLength();
    17. //将字节数组转换为字符串
    18. String s=new String(data,0,length);
    19. System.out.println("接收到来自"+sendIP+"的,端口号为:"+port+"的数据:"+s);
    20. }

    } } ```

    网络模型

    网络模型是计算机网络通讯规范,一般符合以下规则:
    OSI(Open System Interconnection开放系统互连)参考模型;
    TCP/IP参考模型。
    image.png

    TCP协议

    image.png

    案例1

    ```java package com.igeek_04;

/**

  • @author Lynn
  • @create 2020-12-16-14:23 */

import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket;

/**

  • 当前案例演示客户端发送信息,服务器端接收信息 */ public class Server { public static void main(String[] args) throws Exception {

    1. //建立服务器端
    2. ServerSocket serverSocket=new ServerSocket(8888);
    3. //当前是服务器端,所以先获取IO流的同时需要等待客户端发送数据过来
    4. Socket socket= serverSocket.accept();
    5. //建立连接之后,通过Socket中的IO流进行数据传输
    6. InputStream inputStream = socket.getInputStream();
    7. //读取的是一个字节
    8. int read = inputStream.read();
    9. System.out.println((char)read);
    10. //关闭--两个都要关闭
    11. socket.close();
    12. serverSocket.close();

    } } java package com.igeek_04;

/**

  • @author Lynn
  • @create 2020-12-16-14:29 */

import java.io.IOException; import java.io.OutputStream; import java.net.Socket;

/**

  • 客户端 *1.建立客户端
  • 2.连接后,通过socket中的流进行传输
  • 3.关闭 */ public class Client { public static void main(String[] args) throws Exception {

    1. //建立客户端
    2. Socket socket=new Socket("127.0.0.1",8888);
    3. //建立连接后开始传输
    4. OutputStream outputStream=socket.getOutputStream();
    5. //输出数据
    6. outputStream.write(97);
    7. //关闭
    8. outputStream.close();

    } } ```

    案例2—演示跟同桌的初步信息传输

    ```java package com.igeek_05;

/**

  • @author Lynn
  • @create 2020-12-16-14:23 */

import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner;

/**

  • 当前案例演示客户端发送信息,服务器端接收信息 */ public class Server { public static void main(String[] args) throws Exception {

    1. //建立服务器端
    2. ServerSocket serverSocket=new ServerSocket(8888);
    3. //当前是服务器端,所以先获取IO流的同时需要等待客户端发送数据过来
    4. Socket socket= serverSocket.accept();
    5. //建立连接之后,通过Socket中的IO流进行数据传输
    6. InputStream inputStream = socket.getInputStream();
    7. //反复读取客户端发送的数据
    8. int read=-1;
    9. while ((read=inputStream.read())!=-1){
    10. System.out.print((char)read);
    11. }
    12. //接收客户端数据后要返回一个o给客户端
    13. while (true){
    14. OutputStream outputStream=socket.getOutputStream();
    15. Scanner sc=new Scanner(System.in);
    16. System.out.println("请输入数据:");
    17. String content=sc.next();
    18. outputStream.write(content.getBytes());//将字符串转化为字节传输
    19. }
  1. /*//关闭--两个都要关闭
  2. socket.close();
  3. serverSocket.close();*/
  4. }

}

  1. ```java
  2. package com.igeek_05;
  3. /**
  4. * @author Lynn
  5. * @create 2020-12-16-14:29
  6. */
  7. import java.io.InputStream;
  8. import java.io.OutputStream;
  9. import java.net.Socket;
  10. import java.util.Scanner;
  11. /**
  12. * 客户端
  13. *1.建立客户端
  14. * 2.连接后,通过socket中的流进行传输
  15. * 3.关闭
  16. *
  17. * 改进:
  18. * 客户端发送一个字符串:I Love Java信息,接收服务器端返回的一个字母o的响应
  19. *
  20. * void shutdownoutput():禁止输出流,告知对方
  21. */
  22. public class Client {
  23. public static void main(String[] args) throws Exception {
  24. //建立客户端
  25. Socket socket=new Socket("192.168.2.181",8888);
  26. //建立连接后开始传输
  27. OutputStream outputStream=socket.getOutputStream();
  28. //输出数据
  29. while (true){
  30. Scanner sc=new Scanner(System.in);
  31. System.out.println("请输入数据:");
  32. String content=sc.next();
  33. outputStream.write(content.getBytes());//将字符串转换为字节数组
  34. //告诉服务器,不需要发送数据了
  35. socket.shutdownOutput();
  36. //获取服务器端的响应
  37. InputStream inputStream= socket.getInputStream();
  38. byte[] bytes=new byte[1024];
  39. int len=-1;
  40. while ((len= inputStream.read(bytes))!=-1){
  41. String s=new String(bytes,0,len);
  42. System.out.print(s);
  43. }
  44. /*//关闭
  45. outputStream.close();*/
  46. }
  47. }
  48. }

练习1

  1. package Test02;
  2. /**
  3. * @author Lynn
  4. * @create 2020-12-16-20:48
  5. */
  6. import java.io.IOException;
  7. import java.io.InputStream;
  8. import java.net.ServerSocket;
  9. import java.net.Socket;
  10. /**
  11. * 一、 需求说明:使用TCP编写一个网络程序,设置服务器程序监听端口为8002,当于客户端建立后,向客户端发送”hello world”,客户端将信息输出
  12. * 2.2. 操作步骤描述
  13. * 1. 建立项目:day14作业_Test2_2
  14. * 2. 创建TCPServer类,包含main()方法
  15. * 使用ServerSocket创建服务器对象,监听8002端口,调用accept()方法等待客户端连接,当于客户端连接上之后,获取输出流对象,输出”hello world”
  16. * 3. 创建TCPClient类,包含main()方法
  17. * 使用Socket创建客户端对象,指定服务器IP和端口号,与服务器端建立连接后,获取输入流对象,读取数据,并打印.
  18. */
  19. public class TCPServer {
  20. public static void main(String[] args) throws IOException {
  21. //创建服务器对象,建立连接
  22. ServerSocket serverSocket=new ServerSocket(8002);
  23. //调用accept方法
  24. Socket socket= serverSocket.accept();
  25. //获取socket的io流
  26. InputStream in= socket.getInputStream();
  27. //读取数据
  28. byte[] bytes=new byte[1024];
  29. int len=-1;
  30. while ((len=in.read(bytes))!=-1){
  31. String s=new String(bytes,0,len);
  32. System.out.println(s);
  33. }
  34. // in.close();
  35. socket.close();
  36. serverSocket.close();
  37. }
  38. }
  1. package Test02;
  2. import java.io.IOException;
  3. import java.io.OutputStream;
  4. import java.net.Socket;
  5. /**
  6. * @author Lynn
  7. * @create 2020-12-16-20:49
  8. */
  9. public class TCPClient {
  10. public static void main(String[] args) throws IOException {
  11. //建立连接
  12. Socket socket=new Socket("192.168.2.184",8002);
  13. //获取流对象
  14. OutputStream out= socket.getOutputStream();
  15. //输入数据
  16. String s="hello world";
  17. byte[] bytes=s.getBytes();
  18. out.write(bytes);
  19. out.close();
  20. socket.close();
  21. }
  22. }

案例3—文件上传

  1. package com.igeek_06;
  2. /**
  3. * @author Lynn
  4. * @create 2020-12-16-15:13
  5. */
  6. import java.io.FileOutputStream;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. import java.io.OutputStream;
  10. import java.net.ServerSocket;
  11. import java.net.Socket;
  12. /**
  13. * 文件上传,服务器端接收到客户端文件中的数据,向服务器端的另一个文件中写出
  14. * 接收到文件内容,写到某个文件中
  15. *
  16. * 这里的数据是文件中的内容
  17. */
  18. public class Server {
  19. public static void main(String[] args) throws Exception {
  20. //建立服务器端
  21. ServerSocket serverSocket=new ServerSocket(8888);
  22. //获取流
  23. Socket socket = serverSocket.accept();
  24. //建立连接以后获取socket的流
  25. InputStream inputStream=socket.getInputStream();
  26. //获取到上传文件的内容,要有一个文件
  27. FileOutputStream fos=new FileOutputStream("面向对象堂测答案-copy.docx");
  28. //反复使用一个字节读取
  29. int len=-1;
  30. while ((len= inputStream.read())!=-1){
  31. //一次读取一个字节,最终这个文件接受了所有的上传数据
  32. fos.write(len);
  33. }
  34. //关闭IO流
  35. fos.close();
  36. //给客户端返回一个响应
  37. OutputStream out= socket.getOutputStream();
  38. String content="o";
  39. out.write(content.getBytes());
  40. //关闭socket
  41. socket.close();
  42. serverSocket.close();
  43. }
  44. }
  1. package com.igeek_06;
  2. /**
  3. * @author Lynn
  4. * @create 2020-12-16-15:13
  5. */
  6. import java.io.FileInputStream;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. import java.io.OutputStream;
  10. import java.net.Socket;
  11. /**
  12. * 上传文件
  13. * 读取文件内容,发送给服务器端
  14. */
  15. public class Client {
  16. public static void main(String[] args) throws Exception {
  17. //建立客户端
  18. Socket socket=new Socket("localhost",8888);
  19. //建立连接后,获取socket的流
  20. OutputStream out= socket.getOutputStream();
  21. //获取文件对象
  22. FileInputStream fis=new FileInputStream("面向对象堂测答案.docx");
  23. //读取文件内容
  24. int len=-1;
  25. while ((len= fis.read())!=-1){
  26. //输出数据给服务器
  27. out.write(len);
  28. }
  29. //关闭流
  30. fis.close();
  31. //告知服务器,不再发送数据
  32. socket.shutdownOutput();
  33. //获取输入流,接收服务器端的响应
  34. InputStream in= socket.getInputStream();
  35. int read= in.read();
  36. System.out.println((char)read);
  37. socket.close();
  38. }
  39. }

练习2

  1. /**
  2. * @author Lynn
  3. * @create 2020-12-16-21:08
  4. */
  5. import java.io.*;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. /**
  9. * 一、 需求说明:我们来做一个“文件上传案例”,有以下要求:
  10. * 将项目中的一个图片,通过客户端上传至服务器
  11. * 1.2. 操作步骤描述
  12. * 1,创建服务器,等待客户端连接
  13. * 2,创建客户端Socket,连接服务器
  14. * 3,获取Socket流中的输出流,功能:用来把数据写到服务器
  15. * 4,创建字节输入流,功能:用来读取数据源(图片)的字节
  16. * 5,把图片数据写到Socket的输出流中(把数据传给服务器)
  17. * 6,客户端发送数据完毕,结束Socket输出流的写入操作,告知服务器端
  18. * 7,获取Socket的输入流
  19. * 8,创建目的地的字节输出流
  20. * 9,把Socket输入流中的数据,写入目的地的字节输出流中
  21. * 10,获取Socket的输出流, 作用:写反馈信息给客户端
  22. * 11,写反馈信息给客户端
  23. * 12,获取Socket的输入流 作用: 读反馈信息
  24. * 13,读反馈信息
  25. */
  26. public class Server {
  27. public static void main(String[] args) throws IOException {
  28. //创建服务器,建立连接
  29. ServerSocket serverSocket=new ServerSocket(8888);
  30. //调用socket的接收方法
  31. Socket socket=serverSocket.accept();
  32. //接收socket的IO流
  33. InputStream inputStream= socket.getInputStream();
  34. //创建字节输出流
  35. FileOutputStream fos=new FileOutputStream("jackson2-1.jpg");
  36. //读取流中的内容
  37. int len=-1;
  38. while ((len= inputStream.read())!=-1){
  39. fos.write(len);
  40. }
  41. fos.close();
  42. //服务端接收到数据后给客户端一个响应
  43. OutputStream out= socket.getOutputStream();
  44. String s="over";
  45. out.write(s.getBytes());
  46. serverSocket.close();
  47. socket.close();
  48. }
  49. }
  1. import java.io.FileInputStream;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.net.Socket;
  6. /**
  7. * @author Lynn
  8. * @create 2020-12-16-21:08
  9. */
  10. public class Socker {
  11. public static void main(String[] args) throws IOException {
  12. //创建连接
  13. Socket socket=new Socket("127.0.0.1",8888);
  14. //获取流
  15. OutputStream outputStream= socket.getOutputStream();
  16. //读取文件内容
  17. FileInputStream fis=new FileInputStream("jackson2.jpg");
  18. int len=-1;
  19. while ((len= fis.read())!=-1){
  20. outputStream.write(len);
  21. }
  22. fis.close();
  23. //告知服务器不再发送数据了
  24. socket.shutdownOutput();
  25. //客户端接收服务端的响应
  26. InputStream inputStream= socket.getInputStream();
  27. int length=-1;
  28. while ((length= inputStream.read())!=-1){
  29. System.out.print((char)length);
  30. }
  31. socket.close();
  32. }
  33. }