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();
		}
	}
}

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();
		}
	}
}

同步和异步

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

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

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

阻塞和非阻塞

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

  • 阻塞 :ATM排队取款,你只能等待(使用阻塞IO时,Java调用会一直阻塞到读写完成才返回);
  • 非阻塞 :柜台取款,取个号,然后坐在椅子上做其它事,等号广播会通知你办理,没到号你就不能去,你可以不断问大堂经理排到了没有,大堂经理如果说还没到你就不能去(使用非阻塞IO时,如果不能读写Java调用会马上返回,当IO事件分发器通知可读写时再继续进行读写,不断循环直到读写完成
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值