多数情况下,我们的程序是需要同外界通信的,Java中如果我们想要让程序去进行通信,就要用到java.net包下的几个类。在说这几个类之前,我们先大体了解几组概念。

通信有三要素,分别是IP,端口以及通信协议

IP地址 ,可以认为是每台主机的地址,通过这个地址我们就可以找到要通信的主机在哪了。端口号也就是进程的地址,只找到主机我们还是不能通信,我们还需要找到要通信的进程。当主机跟进程都找到之后,我们还需要有一定的传输数据的规范,那么这个规范就是我们所说的传输协议了。我们主要用到的传输协议有两种:UDP协议和TCP协议。
           
UDP:对数据封装,打包,不需建立连接;直接把数据扔过去,每个数据报限制大小在64K,不可靠协议,但速度快。
TCP:先建立连接,形成传输数据的通道,通过三次握手完成连接之后才能传输数据,是可靠协议,效率低。分为客户端和服务端0

一、InetAddress类

此类表示互联网协议 (IP) 地址。有两个子类Inet4Address,Inet6Address,分别代表两种IP地址的结构。IP协议使用的IP 地址是32 位或 128 位无符号数字,它是一种低级协议,UDP 和 TCP 协议都是在它的基础上构建的。

InetAddress没有构造方法,因此我们要通过静态方法来获取该类的对象,这里使用的方法是:

static InetAddress getByName(String host)  在给定主机名或Ip的情况下确定主机的 IP 地址。其中host参数可以是本地主机的名字,可以是一个IP地址,也可以是个域名。还有一种获取本地主机Ip的方式,使用 static InetAddress getLocalHost() 

 

该类还有几个常用的方法:

String getHostAddress() : 返回 IP 地址字符串(以文本表现形式)。 

String getHostName() : 获取此 IP 地址的主机名。 

static InetAddress getLocalHost(): 返回本地主机,可以用来创建本地主机的InetAddress对象。 

 

	private static void method() throws UnknownHostException {
		//传本地主机名参数
		InetAddress address = InetAddress.getByName("七宝");
		System.out.println(address);
		//output: 七宝/172.17.31.30
		System.out.println(address.getHostAddress());
		System.out.println(address.getHostName());
		//output:172.17.31.30
		//	 七宝
		
		//传一个IP参数
		InetAddress address2 = InetAddress.getByName("172.17.31.30");
		System.out.println(address2);
		//output: /172.17.31.30
		System.out.println(address2.getHostAddress());
		System.out.println(address2.getHostName());
		//output:172.17.31.30
		//	 172.17.31.30
		
		//获得本地主机名
		InetAddress address3 = InetAddress.getLocalHost();
		System.out.println(address3);
		//output:七宝/172.17.31.30
		System.out.println(address3.getHostAddress());
		System.out.println(address3.getHostName());
		//output:172.17.31.30
		//	 七宝
		
		//传一个域名参数
		InetAddress address4 = InetAddress.getByName("www.cn.bing.com");
		System.out.println(address4);
		//output:www.cn.bing.com/204.79.197.200
		System.out.println(address4.getHostAddress());
		System.out.println(address4.getHostName());
		//output:204.79.197.200
		//	 www.cn.bing.com
		
		//传bing的IP作参数
		InetAddress address5 = InetAddress.getByName("204.79.197.200");
		System.out.println(address5);
		//output:/204.79.197.200
		System.out.println(address5.getHostAddress());
		System.out.println(address5.getHostName());
		//output:204.79.197.200
		//	 a-0001.a-msedge.net
		
	}

二、使用UDP协议发送接收数据

利用Socket开发网络编程已成为主流,不论是使用UDP还是TCP,我们都将用到Socket。在使用UDP传输数据时,我们需要对数据进行封装,打包。需要用到DatagramSocket类和DatagramPacket类。

java.net.DatagramSocket:此类表示用来发送和接收数据报包的套接字,基于UDP协议。
          DatagramSocket() :创建Socket对象并随机分配端口号,用于发送端。
          DatagramSocket(int port):创建Socket对象并指定端口号port,用于接收端。

java.net.DatagramPacket此类表示数据报包,数据包大小需要小于64K

DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) :构造数据报包,用来将buf数组中从offset开始,长度为 length 的内容打包发送到指定主机上的指定端口号。

DatagramPacket(byte[] buf, int length):构造 DatagramPacket,用来接收长度为 length 的数据包。

使用UPD协议发送数据的步骤
          1. 创建发送端Socket对象
          2. 创建数据并打包
          3. 发送数据包
          4. 释放资源

用到的方法:

除构造方法外,使用DatagramSocket类中的void send(DatagramPacket p) :从此套接字发送数据报包。 

public class SendByUDP {
	public static void main(String[] args) throws IOException {
		// 创建Socket对象
		DatagramSocket ds = new DatagramSocket();

		/* 创建数据并打包 */
		// 创建数据
		String s ="hello upd~~~~~~~~~~~~~~";
		byte[] bys = s.getBytes();
		int length = bys.length;
		InetAddress address = InetAddress.getByName("七宝");
		int port = 8888;

		// 创建数据包
		DatagramPacket p = new DatagramPacket(bys,0,length,address,port);

		// 发送数据
		ds.send(p);

		// 释放资源
		ds.close();
	}
}

使用UPD协议接收数据的步骤

          1. 创建接收端Socket对象
          2. 接收数据
          3. 解析数据
          4. 处理数据
          5. 释放资源

用到的方法:

DatagramSocket类中的void receive(DatagramPacket p)接收数据
           InetAddress getAddress() :获取发送端的IP对象 
           byte[] getData() :获取接收到的数据,也可直接使用创建包对象时的数组
           int getLength() :获取接收到的数据的长度。       

public class ReceiveByUDP {

	public static void main(String[] args) throws IOException {
		// 创建接收端Socket对象,需要指定端口
		DatagramSocket ds = new DatagramSocket(8888);

		// 创建接收数据报包
		byte[] buf = new byte[1024];
		DatagramPacket dp = new DatagramPacket(buf, buf.length);
		
		//接收数据
		ds.receive(dp);//阻塞
		
		// 解析数据
		InetAddress address = dp.getAddress();
		byte[] data = dp.getData();
		int length = dp.getLength();
		
		// 处理数据,可以用数据段的getData方法获取的
		System.out.println("sender:"+ address.getHostAddress()+"---->"+ new String(data,0,length));
		// 也可以用接收数据时,数据包中存放的数组
		System.out.println("sender:"+ address.getHostAddress()+"---->"+ new String(buf,0,length));
		
		// 释放资源
		ds.close();
	}

}

三、使用TCP协议发送接收数据

与UDP不同,我们在使用TCP进行通信时,用到的套接字是Socket和ServerSocket

java.net.Socket:此类实现客户端(发送端)套接字。套接字是两台机器间通信的端点。

java.net.ServerSocket:此类实现服务器(接收端)套接字。服务器套接字等待请求通过网络传入。

客户端发送数据给服务端的步骤

1. 创建客户端Socket对象(创建连接,需要指明Ip和port端口号)
           2. 基于Socket创建输出流对象(发送数据的管道)
           3. 发送数据(以字节的形式发送)
           4. 释放资源

用到的几个方法:

构造函数 Socket(InetAddress address, int port) :创建一个流套接字并将其连接到指定 IP 地址的指定端口号

Socket类中获取输出流的方法 OutputStream getOutputStream() :返回此套接字的输出流。

输出流 OutputStream的 write() 方法,此方法用来发送数据,即将数据写入服务端。

public class SendByTCP {

	public static void main(String[] args) throws IOException {
		// 创建Socket对象(创建连接,需要Ip和port,此处是与本地进行通信)
		Socket s = new Socket(InetAddress.getByName("七宝"), 80);

		// 基于Socket创建输出流对象(发送数据的管道)
		OutputStream os = s.getOutputStream();

		// 发送数据,注意要使用字节流发送
		os.write("hello ,tcp. im coming.".getBytes());

		// 释放资源
		os.close();
		s.close();
	}
}

非常简短的几行代码,我们就可以把一个简易客户端要做的事情写完了,接下来我们再来看服务端如何接收这些数据。

服务端接收来自客户端数据的步骤

1. 创建服务端ServerSocket对象
           2. 监听(阻塞),客户端有连接时,建立连接
           3. 创建输入流对象(管道)
           4. 接收数据
           5. 输出数据
           6. 释放资源(服务端Socket一般不用关闭)

用到的几个方法:

构造函数ServerSocket(int port) :创建绑定到特定端口的服务器套接字。

返回Socket对象的ServerSocket方法 Socket accept() :监听并接收到此套接字的连接。

Socket类中获取输入流的方法 InputStream getInputStream() :返回此套接字的输出流。

输入流 InputStream的 read() 方法,此方法用来接收数据,即输入流来读取数据。

Socket类中的 getInetAddress()方法,此方法用来获取发送端IP。

public class ReceiveByTCP {

	public static void main(String[] args) throws IOException {
		// 创建Socket对象,端口号要与发送端设置的一致
		ServerSocket ss = new ServerSocket(80);
		
		// 监听(阻塞)
		Socket s = ss.accept();
		
		// 创建输入流对象(管道)
		InputStream is = s.getInputStream();
		
		// 接收数据,当数据量大时,我们需要用到循环
		byte[] bys = new byte[1024];
		int len;
		len = is.read(bys);
		
		// 输出数据,调用Socket的getInetAddress方法可获得IP对象
		InetAddress inetAddress = s.getInetAddress();
		System.out.println("sender:" + inetAddress.getHostName() + "====>");
		System.out.println(new String(bys, 0, len));
		
		// 释放资源
		is.close();
		s.close();
	}
}

这样服务端的内容我们也写完了。测试时需要注意一点,我们要先启动服务端的程序之后,再启动客户端,否则服务端不会收到数据。这就好比是谷歌服务器没开,但你去使用google搜东西,这当然是搜不到东西的啦。虽说现在开着,但直接搜仍没反应Σ( ° △ °|||)︴

 

posted on 2018-08-06 18:27  七宝嘤嘤怪  阅读(168)  评论(0编辑  收藏  举报