1 网络通信要素
(1) IP地址:为实现网络中不同设备之间的通信,每个设备的唯一标识就是IP地址,本地回环地址为127.0.0.1。
(2) 端口号:用于标识进程的逻辑地址,不同进程的标识。端口号范围为0~65535,其中0~1023为系统使用或保留端口。
(3) 传输协议:传输协议就是通信的规则,常用的传输层协议为TCP和UDP。UDP协议将数据及源和目的封装到数据报中,不需要建立连接,每个数据报的大小限制在64k内,因其无需连接,所以是不可靠协议,但是速度快;TCP协议建立连接,形成传输数据的通道,可以在连接中进行大数据量的传输,它是通过三次握手完成的连接,所以是可靠的协议,但是效率稍低。
2 InetAddress类
InetAddress类用于标识网络上的硬件资源,表示互联网协议(IP)地址。InetAddress类没有构造方法,所以不能直接new出一个对象;可以通过InetAddress类的静态方法获得InetAddress的对象。InetAddress类的基本示例如下。
package captain;
import java.net.InetAddress;
import java.net.UnknownHostException;
//InetAddress类演示。
public class IPDemo {
public static void main(String[] args) throws UnknownHostException {
//获取本地主机IP地址对象
InetAddress ip1 = InetAddress.getLocalHost();//无构造函数,通过InetAddress的静态方法获取对象
System.out.println(ip1.getHostName());
System.out.println(ip1.getHostAddress());
//获取其他主机IP地址对象
InetAddress ip2 = InetAddress.getByName("www.baidu.com");//无构造函数,通过InetAddress的静态方法获取对象
System.out.println(ip2.getHostName());
System.out.println(ip2.getHostAddress());
}
}
3 Socket
Socket就是为网络服务提供的一种机制。通信的两端都有Socket,网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。网络程序中套接字(Socket)用于将应用程序与端口连接起来。套接字是一个假想的连接装置,就像插插头的设备“插座”,用于连接电器与电路。Java将套接字抽象化为类。
4 UDP传输
基于UDP的通信,信息传递更快,但不提供可靠的保证。使用UDP传递数据时,用户无法知道数据能否正确地到达主机,也不能确定到达目的地的顺序是否与发送的顺序相同。虽然UDP是一种不可靠的协议,但如果需要较快地传输信息,并能容忍小的错误时,可以考虑使用UDP。UDP通信传输的过程将在下面的发送端程序和接收端程序中体现。
UDP发送端程序:
package captain;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
//UDP传输的发送端代码演示。
public class UDPSendDemo {
public static void main(String[] args) throws IOException {
System.out.println("发送端已启动......");
/*创建UDP传输的发送端
*步骤:
*1 建立UDP的Socket服务
*2 定义要发送的数据
*3 将要发送的数据封装到数据报包中
*4 通过UDP的Socket服务将数据报包发送出去
*5 关闭Socket服务
* */
//使用DatagramSocket对象创建UDP的Socket服务,若在其构造函数中没有绑定发送端的端口号,则随机产生一个。
DatagramSocket ds = new DatagramSocket();
//定义要发送的数据,使用字节数组形式。
byte[] b ="这是一个用UDP传输的信息!".getBytes();
//使用DatagramPacket将要发送的数据封装到该数据报包对象中,另外需要指定接收端的IP和端口。
DatagramPacket dp = new DatagramPacket(b, b.length, InetAddress.getByName("127.0.0.1"), 10000);
//通过DatagramSocket对象的send方法将数据报包发送出去。抛出IOException。
ds.send(dp);
//关闭Socket。
ds.close();
}
}
UDP接收端程序:
package captain;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//UDP传输的接收端代码演示。
public class UDPReceiveDemo {
public static void main(String[] args) throws IOException {
System.out.println("接收端已启动......");
/*创建UDP传输的接收端
*步骤:
*1 建立UDP的Socket服务
*2 创建一个空的字节数组
*3 创建一个接收上面字节数组的数据报包
*4 使用UDP的Socket服务接收数据
*5 使用数据报包对象的方法解析接收到的数据
*6 关闭Socket服务
* */
//使用DatagramSocket创建UDP的Socket服务,需要绑定接收端的端口(与发送端指定的一致),否则接收不到。
DatagramSocket ds = new DatagramSocket(10000);
//创建一个空的字节数组,用于存储接收到的数据。
byte[] b = new byte[1024];
//使用DatagramPacket创建一个接收上面字节数组的数据报包对象,方便后面使用其方法解析接收到的数据。
DatagramPacket dp = new DatagramPacket(b, b.length);
//使用DatagramSocket对象的receive方法将接收到的数据存储到上面的数据报包中。
ds.receive(dp);//此方法在接收到数据报包之前会一直阻塞
//使用数据报包对象的方法解析接收到的数据。
String ip = dp.getAddress().getHostAddress();//获取发送端字符串形式的IP地址
int port = dp.getPort();//获取发送端的端口号
String text = new String(b, 0, dp.getLength());//获取发送端发送的数据
System.out.println("发送端的IP"+":"+ip+" "+"发送端的port"+":"+port+" "+"发送端的数据"+":"+text);
//关闭Socket。
ds.close();
}
}
UDP发送端程序(加入I/O流):
package captain;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
//UDP传输的发送端代码演示。加入I/O流,从键盘录入数据,可以发送多条数据。
public class UDPSendDemo2 {
public static void main(String[] args) throws IOException {
System.out.println("发送端已启动......");
/*创建UDP传输的发送端
*步骤:
*1 建立UDP的Socket服务
*2 定义要发送的数据
*3 将要发送的数据封装到数据报包中
*4 通过UDP的Socket服务将数据报包发送出去
*5 关闭Socket服务
* */
//使用DatagramSocket对象创建UDP的Socket服务,若在其构造函数中没有绑定发送端的端口号,则随机产生一个。
DatagramSocket ds = new DatagramSocket();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//键盘录入
String line = null;
while((line=br.readLine())!=null){//按行循环读取键盘录入的内容
//定义要发送的数据,使用字节数组形式。
//byte[] b ="这是一个用UDP传输的信息!".getBytes();
byte[] b = line.getBytes();
//使用DatagramPacket将要发送的数据封装到该数据报包对象中,另外需要指定接收端的IP和端口。
DatagramPacket dp = new DatagramPacket(b, b.length, InetAddress.getByName("127.0.0.1"), 10000);
//通过DatagramSocket对象的send方法将数据报包发送出去。抛出IOException。
ds.send(dp);
if("over".equals(line))//结束标识
break;
}
//关闭Socket。
ds.close();
}
}
UDP接收端程序(加入I/O流):
package captain;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//UDP传输的接收端代码演示。可以接收多条数据。
public class UDPReceiveDemo2 {
public static void main(String[] args) throws IOException {
System.out.println("接收端已启动......");
/*创建UDP传输的接收端
*步骤:
*1 建立UDP的Socket服务
*2 创建一个空的字节数组
*3 创建一个接收上面字节数组的数据报包
*4 使用UDP的Socket服务接收数据
*5 使用数据报包对象的方法解析接收到的数据
*6 关闭Socket服务
* */
//使用DatagramSocket创建UDP的Socket服务,需要绑定接收端的端口(与发送端指定的一致),否则接收不到。
DatagramSocket ds = new DatagramSocket(10000);
while(true){//无限循环接收多个数据报包
//创建一个空的字节数组,用于存储接收到的数据。
byte[] b = new byte[1024];
//使用DatagramPacket创建一个接收上面字节数组的数据报包对象,方便后面使用其方法解析接收到的数据。
DatagramPacket dp = new DatagramPacket(b, b.length);
//使用DatagramSocket对象的receive方法将接收到的数据存储到上面的数据报包中。
ds.receive(dp);//此方法在接收到数据报包之前会一直阻塞
//使用数据报包对象的方法解析接收到的数据。
String ip = dp.getAddress().getHostAddress();//获取发送端字符串形式的IP地址
int port = dp.getPort();//获取发送端的端口号
String text = new String(b, 0, dp.getLength());//获取发送端发送的数据
System.out.println("发送端的IP"+":"+ip+" "+"发送端的port"+":"+port+" "+"发送端的数据"+":"+text);
//关闭Socket。
//ds.close();//这里不能关闭Socket
}
}
}
另:可以加入多线程,使发送功能类和接收功能类分别都实现Runnable接口,开启发送和接收两个线程,实现一端既可以发送数据,同时又可以接收数据。
5 TCP传输
基于TCP的通信,需要通过Socket和ServerSocket对象分别建立客户端和服务端,建立连接后,通过Socket中的IO流进行数据的传输,最后需要关闭socket。TCP通信传输的过程将在下面的客户端程序和服务端程序中体现。TCP客户端程序:package captain;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
//TCP传输的客户端代码演示。
public class TCPClientDemo {
public static void main(String[] args) throws IOException {
/*创建TCP传输客户端
*步骤:
*1 使用Socket对象创建TCP客户端的socket服务,最好在创建Socket对象时就指定目的地址和端口。
*2 如果连接建立成功,就说明数据传输通道已建立。该通道就是socket流,想要输出或输入流对象,
* 可以找Socket对象的两个方法获取:getOutputStream()和getInputStream()。
*3 使用输出流,将数据写出。
*4 关闭资源。
* */
//创建客户端socket服务
Socket socket = new Socket("127.0.0.1", 10000);
//获取socket流中的输出流
OutputStream os = socket.getOutputStream();
//使用输出流的方法写出数据
os.write("这是一个TCP客户端的演示信息!".getBytes());
//关闭资源
socket.close();
}
}
TCP服务端程序:package captain;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//TCP传输的服务端代码演示。
public class TCPServerDemo {
public static void main(String[] args) throws IOException {
/*创建TCP传输服务端
*步骤:
*1 通过ServerSocket对象创建服务端socket服务。服务端必须对外提供一个端口,否则客户端无法连接。
*2 获取连接过来的客户端对象。
*3 通过客户端对象获取socket流,读取客户端发来的数据。
*4 关闭资源。关客户端、关服务端。
* */
//创建服务端socket服务
ServerSocket ss = new ServerSocket(10000);
//获取连接过来的客户端对象
Socket s = ss.accept();//阻塞式
String ip = s.getInetAddress().getHostAddress();//获取客户端的IP地址
//通过Socket对象获取输入流,读取客户端发送的数据
InputStream is = s.getInputStream();
byte[] b = new byte[1024];
int len = is.read(b);
String text = new String(b, 0, len);
System.out.println(ip+":"+text);
//关闭资源
s.close();
ss.close();
}
}
6 URL
URL(Uniform Resource Locator)统一资源定位符,表示Internet上某一资源的地址。URL由两部分组成:协议名称和资源名称,中间用冒号隔开。java.net包中提供了URL类。通过URL对象的openStream()方法可以得到指定资源的输入流。通过输入流可以读取和访问网络上的数据。URL类演示示例如下。package captain;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
//URL类演示
public class URLDemo {
public static void main(String[] args) throws IOException {
//创建URL对象
String str_url = "http://www.baidu.com";
URL url = new URL(str_url);
//使用URL对象的openStream()方法返回一个字节输入流
InputStream is = url.openStream();
//转换为字符输入流,读取网页资源
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String str = null;
while((str=br.readLine())!=null){
System.out.println(str);
}
}
}