• 2022-08-11 学习日记(31st day)网络通信(网络编程)


    目录

    网络通信

    服务器:

    客户端:

    实例:

    实例二: 

    通过UDP(不可靠的传输协议)进行传输

    URL

    两种架构: 

    web服务器

    我们按照http协议的格式封装一个报文,输入给网页

    重定向


    网络通信

    提到网络,我们就不得不提起两个东西:服务器和客户端

    服务器:是一台电脑。一台低配的电脑

    客户端:是一台电脑,也可以是手机,平板,网页

    我们即将要在我们自己的电脑上搭建服务器环境,我们的电脑既是服务器,也是客户端

    Socket编程:

    Socket编程是建立在TCP/IP协议上的。(我会单独写一篇文章解释TCP/IP协议等关于网络的东西)

    怎么在网络环境下访问其他的主机?

    通过IP地址+端口号形式可以访问其他的主机。

    查看自己的电脑在当前网络环境下的IP地址:

    通过指令控制台CMD:ipconfig查看ipv4地址,是当前区域网下的ip地址

    eg:192.168.1.1

    一台电脑可以有好多个端口号,每个端口号对应的程序也可以不同

    eg:192.168.1.1:8888

          192.168.1.1:8080

    我们接下来就要在我们的电脑上开辟一个端口号,这个端口号就是服务器的端口

    然后我们再构建一个客户端,来通过ip地址+端口号来访问到服务器

    Socket通信的服务端也是一个对象:ServerSocket类

    服务器:

    创建一个服务器对象,绑定在8888端口:

     ServerSocket serverSocket = new ServerSocket(8888);

    服务器等待客户端连接:

    Socket socket = serverSocket.accept();

    读取客户端发送过来的信息

    1. InputStream inputStream = socket.getInputStream();
    2. byte [] buffer = new byte[1024 * 1024];//定义一次读取1024*1024
    3. int len;
    4. while((len = inputStream.read(buffer)) != -1){
    5. System.out.println("服务器已接收客户端的数据:" + new String(buffer,0,len));
    6. }

    别忘了释放资源:

    1. inputStream.close();
    2. socket.close();

    客户端:

    创建一个Socket通信的客户端

    Socket socket = new Socket();

    第一个参数是获取当前电脑的ip地址,第二个参数是服务器的端口号

    socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(),8888));

    客户端发送数据给服务器

    1. OutputStream outputStream = socket.getOutputStream();
    2. String data = "hello server!";
    3. outputStream.write(data.getBytes());
    4. System.out.println("客户端已发送数据:" + data);
    5. outputStream.close();
    6. socket.close();

    实例:

    1. public class Test01 {
    2. @Test
    3. public void server() throws IOException {
    4. //创建了一个服务器对象,绑定在8888端口
    5. ServerSocket serverSocket = new ServerSocket(8888);
    6. System.out.println("服务器已启动...");
    7. //服务器在等待客户端连接
    8. Socket socket = serverSocket.accept();
    9. System.out.println(socket);
    10. //读取客户端发送来的信息
    11. InputStream inputStream = socket.getInputStream();
    12. byte [] buf = new byte[1024*1024];
    13. int len;
    14. while((len = inputStream.read(buf))!=-1){
    15. System.out.println(new String(buf,0,len));
    16. }
    17. inputStream.close();
    18. socket.close();
    19. }
    20. @Test
    21. public void client() throws IOException {
    22. //创建了一个Socket的客户端
    23. Socket socket = new Socket();
    24. //第一个参数就是获取当前电脑的ip地址
    25. //第二个参数就是服务器的端口号
    26. socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(),8888));
    27. System.out.println("客户端以连接服务器");
    28. //客户端发送数据给服务器
    29. OutputStream outputStream = socket.getOutputStream();
    30. outputStream.write("heello,小五,我是你爹".getBytes(StandardCharsets.UTF_8));
    31. String data = "hello server!";
    32. outputStream.write(data.getBytes());
    33. System.out.println("客户端已发送数据:" + data);outputStream.close();
    34. socket.close();
    35. }
    36. }

    实例运行结果:

    服务器:

    客户端:

    实例二: 

    我们平常正常通信的时候,像邮件,你发送之后对方是否收到,会有一个提示

    我们就做一个客户端收到信息后给服务器发送一个收到了的信息:

    1. public class Ch02 {
    2. @Test
    3. public void server() throws IOException {
    4. // 创建了一个服务器对象,绑定在8888端口
    5. ServerSocket serverSocket = new ServerSocket(8888);
    6. System.out.println("服务器已启动...");
    7. // 服务器在等待客户端连接
    8. Socket socket = serverSocket.accept();
    9. // 读取客户端发送过来的信息
    10. InputStream inputStream = socket.getInputStream();
    11. // InputStream inputStream1 = new FileInputStream("");
    12. OutputStream outputStream = new FileOutputStream("d:/Pointofix.exe");
    13. // 我们要再获取一个输出流,这个输出流是为了给客户端返回数据
    14. OutputStream clientOutputStream = socket.getOutputStream();
    15. byte [] buffer = new byte[1024 * 1024];
    16. int len;
    17. while((len = inputStream.read(buffer)) != -1){
    18. // 接收信息,接的是什么信息?
    19. // 看输入流是怎么来的?
    20. // 我们现在的输入流是怎么来的?
    21. // 通过socket获取到的
    22. // socket是怎么来的?
    23. // socket是通过服务器启动之后,接到的客户端连接
    24. // 我们的输入流就是客户端的输入流
    25. // 因为我们现在接收的是一个文件
    26. // 我们需要把这个文件另存
    27. // 我们需要构建一个输出流,把这个文件保存在硬盘上
    28. outputStream.write(buffer,0,len);
    29. }
    30. System.out.println("文件接收成功...");
    31. // 给客户端返回一个数据
    32. clientOutputStream.write("文件已成功保存到服务器...".getBytes());
    33. // 释放资源
    34. inputStream.close();
    35. outputStream.close();
    36. socket.close();
    37. }
    38. @Test
    39. public void client() throws IOException {
    40. // 创建了一个Socket通信的客户端
    41. Socket socket = new Socket();
    42. // 第一个参数就是获取当前电脑的IP地址
    43. // 第二个参数就是服务器的端口号
    44. socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(),8888));
    45. // 客户端发送数据给服务器
    46. OutputStream outputStream = socket.getOutputStream();
    47. File file = new File("e:/Pointofix.exe");
    48. InputStream inputStream = new FileInputStream(file);
    49. // 我们现在要读取的是服务器的数据,就需要构建一个从服务器来的输入流
    50. InputStream serverInputStream = socket.getInputStream();
    51. // 要发送的文件
    52. byte [] buf = new byte[1024 * 1024];
    53. int len;
    54. while((len = inputStream.read(buf)) != -1){
    55. // 把读取到的文件循环发送给服务器
    56. // 输出流把文件写出去,写到哪里去了?
    57. // 输出流,首先要看这个输出流是怎么来的,就能够确定这个内容要输出到哪里?
    58. // 我们现在的输出流是通过socket获取到的
    59. // 所以说我们现在的写的操作就是把文件写给服务端
    60. outputStream.write(buf,0,len);
    61. }
    62. System.out.println("文件发送成功...");
    63. // 要通知服务器文件已发送完毕,下面的操作是等待服务器的回复
    64. // 通知服务器数据已经发送完毕
    65. socket.shutdownOutput();
    66. // 接收服务器回传的数据
    67. byte [] serverBuf = new byte[1024 * 1024];
    68. int serverLen;
    69. while((serverLen = serverInputStream.read(serverBuf)) != -1){
    70. System.out.println(new String(serverBuf,0,serverLen));
    71. }
    72. inputStream.close();
    73. outputStream.close();
    74. socket.close();
    75. }
    76. }

     我在中间加了一个socket.shutdownOutput().

    为什么,因为服务器的文件已经发送了,但是还是要执行接收服务器回传的数据,所以你需要告诉服务器已经完毕了,要不然他一直服务器无法知道客户端是否收到,而客户端也不知道是否上传到服务器,就会形成死锁的情况,所以添加有个shutdownOutput,是为了通知服务器文件已经发送完毕。

     

    通过UDP(不可靠的传输协议)进行传输

    通过UDP发送的数据报文,操作起来很简单,但是弊端也很明显,就是客户端发送了数据,也不管那边接没接收到,就自己结束了,不管那边。用实例展示:

    1. public class Ch03 {
    2. @Test
    3. public void client() throws IOException {
    4. DatagramSocket socket = new DatagramSocket();
    5. String str = "我通过UDP协议发送的消息...";
    6. byte [] data = str.getBytes();
    7. // 构建成了一个数据报文
    8. // 第一个参数就是要发送的数据
    9. // 第二个参数从哪开始发
    10. // 第三个参数发多长
    11. // 第四个参数指定服务器的ip地址
    12. // 第五个参数是服务器的端口号
    13. DatagramPacket packet = new DatagramPacket(data,
    14. 0,data.length,
    15. InetAddress.getLocalHost(),9999);
    16. // 发送数据
    17. socket.send(packet);
    18. System.out.println("数据发送成功...");
    19. socket.close();
    20. }
    21. @Test
    22. public void server() throws IOException {
    23. // 服务器指定端口号
    24. DatagramSocket socket = new DatagramSocket(9999);
    25. byte [] buffer = new byte[1024 * 1024];
    26. DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
    27. // 接收客户端发过来的数据
    28. socket.receive(packet);
    29. System.out.println(new String(packet.getData(),0,packet.getLength()));
    30. socket.close();
    31. }
    32. }

    如果服务器没开,UDP发送的协议也会显示发送成功,但是服务器并没有响应,也没有接收到这条数据。

    URL

    URL:https://www.163.com/,对应着互联网的一个资源网址

    URL:https://192.168.1.1:8888/goods        协议   主机名    端口号    资源地址

    URL url = new URL("https://192.168.1.1:8888/demo/list.html?usenrame=123&password=123456");

    常用的方法:

    url.getFile()获取URL文件名
    url.getHost()获取主机名
    url.getPath()获取路径部分
    url.getPort()获取端口号
    url.getQuery()获取查询部分
    url.getProrocol()获取协议
    1. public static void main(String[] args) {
    2. try {
    3. URL url = new URL("https://192.168.1.1:8888/demo/list.html?usenrame=123&password=123456");
    4. System.out.println(url.getProtocol());
    5. System.out.println(url.getFile());
    6. System.out.println(url.getHost());
    7. System.out.println(url.getPort());
    8. System.out.println(url.getPath());
    9. System.out.println(url.getQuery());
    10. } catch (Exception e) {
    11. throw new RuntimeException(e);
    12. }
    13. }

    运行结果: 

     获取本地主机名/获取本地ip:

    1. InetAddress i = InetAddress.getLocalHost();
    2. System.out.println(i);
    3. System.out.println(i.getHostName());
    4. System.out.println(i.getHostAddress());

     设置ip地址:

    InetAddress inet1 = InetAddress.getByName("192.168.1.1");

    两种架构: 

    C/S架构:Client/Server客户端/服务器,QQ,360,腾讯会议,游戏

    B/S架构:Browser/Server浏览器/服务器,

    java主要要做的就是架构中的Server端

    1.静态资源:所有用户访问后,得到的结果都是一样的。html

    2.动态资源:每个用户访问后,得到的结果可能不一样。爱奇艺,腾讯,个人空间...

    web服务器

    接收用户的请求,处理请求,给出响应。

    通过浏览器访问我们的ServerSocket服务器,我们通过浏览器给我们的ServerSocket服务器发起了请求
    我要访问服务器!!!通过IP地址 + 端口号
    本机的IP地址:

    1.cmd---ipconfig
    2.127.0.0.1---本机(个人建议,任何情况都好使)
    3.localhost---本机(前提条件:你的电脑要联网,激活一下网卡)                

    1. public class Demo2 {
    2. public static void main(String[] args) throws IOException {
    3. ServerSocket serverSocket = new ServerSocket(8080);
    4. // 等待客户端的连接
    5. Socket accept = serverSocket.accept();
    6. // 获取一个输入流来读取客户端发送的数据
    7. InputStream inputStream = accept.getInputStream();
    8. byte [] buf = new byte[1024];
    9. int len;
    10. while((len = inputStream.read(buf)) != -1){
    11. System.out.println(new String(buf,0,len));
    12. }
    13. inputStream.close();
    14. accept.close();
    15. }
    16. }

    打开网页输入127.0.0.1:8080
    我们通过浏览器访问我们的ServerSocket,得到了一堆信息,看不懂。

    GET / HTTP/1.1
    Host: 127.0.0.1:8080
    Connection: keep-alive
    sec-ch-ua: "Chromium";v="104", " Not A;Brand";v="99", "Microsoft Edge";v="104"
    sec-ch-ua-mobile: ?0
    sec-ch-ua-platform: "Windows"
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.81 Safari/537.36 Edg/104.0.1293.47
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,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,en;q=0.8,en-GB;q=0.7,en-US;q=0.6

    其实发送过来的信息,报文。浏览器传递过来的一些消息。
    User-Agent:告诉服务器我是从什么样的客户端来的。
    Host: 127.0.0.1:8080,主机地址,目标主机。
    貌似浏览器也是通过Socket和我们的服务器建立了TCP连接
    我们不妨把浏览器给我们的服务器发送的信息称之为“请求”,
    而且这个请求格式满足了http的协议。
    请求:客户端--->服务器
    响应:服务器--->客户端
    我需要给浏览器一个响应!!!
    我们一般情况下,给浏览器做出响应,需要遵循浏览器的格式要求:

    我们按照http协议的格式封装一个报文,输入给网页

    1. public static void main(String[] args) throws IOException {
    2. ServerSocket serverSocket = new ServerSocket(8888);
    3. System.out.println("服务器启动成功...");
    4. Socket server = serverSocket.accept();
    5. OutputStream outputStream = server.getOutputStream();
    6. // 按照http协议的格式封装一个报文数据
    7. String response = "HTTP/1.1 200 OK\r\n"+
    8. "Content-Length: 39\r\n" +
    9. "Content-Type: text/html;charset=UTF-8\r\n\r\n" +
    10. "

      hello server

      "
      ;
    11. outputStream.write(response.getBytes());
    12. outputStream.flush();
    13. // 这个流不要着急关,因为突然的关闭会导致浏览器和服务器断开连接
    14. }

    你会发现我在里面写的

    标签在网页中显现出来了:

    重定向

     重定向会重新定位到新的页面,而且地址栏的地址也会随之变化。

    1. public static void main(String[] args) throws IOException {
    2. ServerSocket serverSocket = new ServerSocket(8888);
    3. System.out.println("服务器启动成功...");
    4. Socket server = serverSocket.accept();
    5. OutputStream outputStream = server.getOutputStream();
    6. // 按照http协议的格式封装一个报文数据
    7. String response = "HTTP/1.1 302 Moved Temporarily\r\n"+
    8. "Location: https://www.baidu.com\r\n\r\n";
    9. outputStream.write(response.getBytes());
    10. outputStream.flush();
    11. // 这个流不要着急关,因为突然的关闭会导致浏览器和服务器断开连接
    12. }

     

  • 相关阅读:
    中断上下文使用spin_lock进程上下文使用spin_lock_irqsave的原因?
    头歌的数据库的第二次作业的答案
    调试篇——断点与单步
    基于SSM+Vue的舞蹈网站
    【Linux私房菜】—— 远程登录与数据传输、Vim与Vi的基础用法、关机与重启、登录与注销
    RK3588安装python3.11(ubuntu18.04)
    党建展馆vr仿真解说员具有高质量的表现力和互动性
    一文读懂Web3 结算协议 Zebec Protocol 的商业模式与发展前景
    第二证券|疫情扰动叠加需求不足,11月制造业PMI回落至48%
    windows10系统下指定用户配置FTP服务器及多用户登录
  • 原文地址:https://blog.csdn.net/weixin_49627122/article/details/126291798