• Java 网络编程——Java筑基


    网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。
    java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节。


    前言

    java.net包中提供了两种常见的网络协议支持:

    • TCP:Transmission Control Protocol,传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通讯协议,TCP层位于IP层之上,应用层之下的中间层。TCP保障了两个应用程序之间的可靠通信,通常用于互联网协议,称之为TCP/IP。
    • UDP:User Datagram Protocol,用户数据报协议,位于OSI模型的传输层,一个无连接的协议,提供了应用程序之间要发送数据的数据报,由于UDP缺乏可靠性的且属于无连接的协议,因此应用程序通常需要设计冗余措施,允许接受一些丢失、错误或者重复的数据包。

    Socket编程

    套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。

    当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。

    java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。

    以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:

    • 服务器server实例化一个ServerSocket对象,表示通过服务器上的端口通信。
    • 服务器调用ServerSocket类的accept方法,该方法会阻塞等待,知道客户端连接到服务器server的给定端口。
    • 服务器等待时候,客户端实例化一个Socket对象,指定服务器的名称和端口号请求连接。
    • Socket类的构造函数会试图把客户端连接到指定的服务器和端口号,若通信建立,则在客户端创建一个socket对象能够和服务器进行通信。
    • 服务器端,accept方法返回服务器上一个新的socket引用,这个socket会连接到客户端的socket。

    连接建立之后,通过IO流进行通信,每一个socket都会有一个输出流和一个输入流,客户端的输出流会连接到server的输入流,而客户端client的输入流连接到server服务端的输出流。
    TCP是一个双向的通信协议,因此数据可以通过两个数据流在同一个时间发送,下面会给出部分方法。


    ServerSocket 类的方法

    服务器应用程序通过使用 java.net.ServerSocket 类以获取一个端口,并且侦听客户端请求。

    • public ServerSocket(int port) throws IOException:
      创建绑定到特定端口的服务器套接字。
    • public ServerSocket(int port, int backlog) throws IOException
      利用指定的backlog创建服务器套接字并且绑定到指定的本地端口号。
    • public ServerSocket(int port, int backlog, InetAddress address) throws IOException
      使用指定端口、监听backlog和需要绑定到本地IP地址创建服务器。
    • public ServerSocket() throws IOException
      创建非绑定服务器套接字。

    下面给出ServerSocket的常用方法:

    • public int getLocalPort():返回该套接字在其上侦听的端口号。
    • public Socket accept() throws IOException:监听并且接受套接字的连接。
    • public void setSoTimeout(int timeout):通过指定超时值启用或者禁用SO_TIMEOUT,毫秒单位。
    • public void bind(SocketAddress host, int backlog):将ServerSocket绑定到特定地址(IP 地址和端口号)。

    Socket类方法

    java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字。客户端要获取一个 Socket 对象通过实例化 ,而服务器获得一个 Socket 对象则通过 accept() 方法的返回值。

    • public Socket(String host, int port) throws UnknownHostException, IOException.
      创建一个流套接字并将其连接到指定主机上的指定端口号。
    • public Socket(InetAddress host, int port) throws IOException
      创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
    • public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException.
      创建一个套接字并将其连接到指定远程主机上的指定远程端口。
    • public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException.
      创建一个套接字并将其连接到指定远程地址上的指定远程端口。
    • public Socket()
      通过系统默认类型的SocketImpl创建未连接的套接字。

    下面在给出Socket的常用方法:

    • public void connect(SocketAddress host, int timeout) throws IOException:把该套接字连接到服务器,指定一个超时数值。
    • public InetAddress getInetAddress():返回套接字连接的地址。
    • public int getPort():返回套接字连接到的远程端口。
    • public int getLocalPort():返回套接字绑定的本地端口。
    • public SocketAddress getRemoteSocketAddress():返回此套接字连接的端点的地址,如果未连接则返回 null。
    • public InputStream getInputStream() throws IOException:返回此套接字的输入流。
    • public OutputStream getOutputStream() throws IOException:返回套接字的输出流。
    • public void close() throws IOException:关闭套接字。

    InetAddress 类的方法

    这个类表示互联网协议IP地址,给出常用方法:

    • static InetAddress getByAddress(byte[] addr):
      在给定原始 IP 地址的情况下,返回 InetAddress 对象。
    • static InetAddress getByAddress(String host, byte[] addr)
      根据提供的主机名和 IP 地址创建 InetAddress。
    • static InetAddress getByName(String host)
      在给定主机名的情况下确定主机的 IP 地址。
    • String getHostAddress() :
      返回 IP 地址字符串(以文本表现形式)。
    • String getHostName()
      获取此 IP 地址的主机名。
    • static InetAddress getLocalHost()
      返回本地主机。
    • String to String():
      IP地址转换为String。

    Server代码:

    package javaNet;
    
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class ServerSocketTest extends Thread {
    	private ServerSocket serverSocket;
    
    	public ServerSocketTest(int port) throws Exception {
    		serverSocket = new ServerSocket(port);
    		serverSocket.setSoTimeout(10000);
    	}
    
    	@Override
    	public void run() {
    		while (true) {
    			try {
    				System.out.println("等待远程连接,端口号为:" + serverSocket.getLocalPort() + "...");
    				Socket server = serverSocket.accept();
    				System.out.println("远程主机地址:" + server.getRemoteSocketAddress());
    				DataInputStream in = new DataInputStream(server.getInputStream());
    				System.out.println(in.readUTF());
    				DataOutputStream out = new DataOutputStream(server.getOutputStream());
    				out.writeUTF("谢谢连接我:" + server.getLocalSocketAddress() + "\nGoodbye!");
    				server.close();
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    	}
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		int port = 8888;
    		try {
    			Thread t = new ServerSocketTest(port);
    			t.run();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    Client代码:

    package javaNet;
    
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
    
    public class ClientSocket {
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		String serverName = "localhost";
    		int port = 8888;
    		try {
    			System.out.println("连接到主机:" + serverName + " 端口号:" + port);
    			Socket client = new Socket(serverName, port);
    			System.out.println("远程主机地址:" + client.getRemoteSocketAddress());
    			OutputStream outToServer = client.getOutputStream();
    			DataOutputStream out = new DataOutputStream(outToServer);
    
    			out.writeUTF("Hello from " + client.getLocalSocketAddress());
    			InputStream inFromServer = client.getInputStream();
    			DataInputStream in = new DataInputStream(inFromServer);
    			System.out.println("服务器响应:" + in.readUTF());
    
    			client.close();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    同步和异步

    同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发IO 操作并等待或者轮询的去查看IO 操作是否就绪而异步是指用户进程触发IO 操作以后便开始做自己的事情,而当IO 操作已经完成的时候会得到IO 完成的通知。

    • 同步 : 自己亲自出马持银行卡到银行取钱(使用同步 IO 时,Java 自己处理IO 读写);

    • 异步 : 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO 时,Java 将 IO 读写委托给OS 处理,需要将数据缓冲区地址和大小传给OS(银行卡和密码),OS 需要支持异步IO操作API);

    阻塞和非阻塞

    阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作方法的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入方法会立即返回一个状态值。

    • 阻塞 :ATM排队取款,你只能等待(使用阻塞IO时,Java调用会一直阻塞到读写完成才返回);
    • 非阻塞 :柜台取款,取个号,然后坐在椅子上做其它事,等号广播会通知你办理,没到号你就不能去,你可以不断问大堂经理排到了没有,大堂经理如果说还没到你就不能去(使用非阻塞IO时,如果不能读写Java调用会马上返回,当IO事件分发器通知可读写时再继续进行读写,不断循环直到读写完成
  • 相关阅读:
    c++——map和set的封装
    图书目录管理系统(C++)
    实时数仓混沌演练实践
    【HDLBits 刷题 15】Verification Writing Testbenches
    Java-开发技术框架-Mybatis --- HelloWorld强化
    vue实际项目中遇到的问题和解决方式
    119.(前端)商品管理增加基本信息布局——model与ref与prop概念介绍、使用级联选择器与tab中使用form表单
    (3)MyBatis-Plus待开发
    子查询---
    图像增强之灰度变换
  • 原文地址:https://blog.csdn.net/qq_42544728/article/details/126380062