1. 网络通信要素
- 网络中的主机间实现通信需要指明地址( IP、端口号)并遵守一定的网络通信协议(HTTP、FTP、TCP、UDP、IP 等)
- OSI 7层模型、TCP/IP 5层模型、对应的网络协议
- IP地址
IP地址用于唯一标识 Internet 上的计算机。
IPV4:32位(4个字节),表示范围为0—2^32。以点分十进制表示,如192.168.0.1
IPV6:128位(16个字节),表示范围为0—2^128。写成8个无符号整数,每个整数用四个十六进制位表示,数之间用冒号(:)分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984 - 端口号
端口号用于标识正在计算机上运行的进程
不同的进程有不同的端口号,规定端口号范围 0~65535。
公认端口:0~1023。被预先定义的服务通信占用(如:HTTP占用端口80,FTP占用端口21,Telnet占用端口23)
注册端口:1024~49151。分配给用户进程或应用程序(如:Tomcat占用端口8080,MySQL占用端口3306)
动态/私有端口:49152~65535
2. InetAddress类
- InetAddress类对象含有一个Internet主机地址的域名和IP地址
- Internet上的主机的两种表示地址方式:①域名(hostName) ②IP 地址(hostAddress) DNS用于将IP地址解析为域名
- 常用方法
InetAddress类没有提供公共的构造器,而是提供了如下静态方法来获取实例
static InetAddress getByName(String host) //确定主机名称的IP地址
static InetAddress getByAddress(String host, byte[] addr)//根据提供的主机名和IP地址创建InetAddress
String getHostName() //获取此IP地址的主机名
String getHostAddress() //返回文本显示中的IP地址字符串
static InetAddress getLocalHost() //返回本地主机的地址
3. Socket
- 端口号与IP地址的组合得到网络套接字:Socket
- Socket允许程序把网络连接当成一个流使得数据在两个Socket间通过IO传输
- 一般主动发起通信的应用程序是客户端,等待通信请求的为服务器端
- Socket分类:
①流套接字(stream socket ):使用TCP提供可依赖的字节流服务
② 数据报套接字(datagram socket):使用UDP提供“尽力而为”的数据报服务 - 构造器、常用方法
public Socket(InetAddress address,int port)//创建一个流套接字并将其连接到指定的IP地址、指定端口号
public Socket(String host,int port)//创建一个流套接字并将其连接到指定主机上的指定端口号
public InputStream getInputStream()//返回此套接字的输入流,可以用于接收网络消息
public OutputStream getOutputStream()//返回此套接字的输出流,可以用于发送网络消息
public InetAddress getInetAddress()//此套接字连接到的远程 IP 地址;如果套接字是未连接的则返回 null。
public InetAddress getLocalAddress()//获取套接字绑定的本地地址。即本端的IP地址
public int getPort()//此套接字连接到的远程端口号;如果尚未连接套接字则返回 0。
public int getLocalPort()//返回此套接字绑定到的本地端口。 如果尚未绑定套接字,则返回 -1。
public void close()//关闭此套接字。套接字被关闭后,便不可在以后的网络连接中使用(即无法重新连接或重新绑定)。
//需要创建新的套接字对象。 关闭此套接字也将会关闭该套接字的 InputStream 和OutputStream。
public void shutdownInput()//禁用此套接字的输入流,即不能再从此套接字的输入流中接收任何数据
public void shutdownOutput()//禁用此套接字的输出流。对于 TCP 套接字,任何以前写入的数据都将被发送,并且后跟 TCP 的正常连接终止序列。
//如果在套接字上调用 shutdownOutput() 后写入套接字输出流,则该流将抛出 IOException。 即不能通过此套接字的输出流发送任何数据。
4. 基于Socket的TCP网络编程
- 使用TCP协议前必须先建立TCP连接以形成传输数据通道
TCP是可靠传输前,传输前会“三次握手”,传输后会" 四次挥手 "
TCP传输完毕后需释放已建立的连接
- 基于Socket的TCP编程
(1) 客户端
①创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。
②打开连接到 Socket 的输入 / 出流进行数据传输: 使用getInputStream()方法获得输入流,使用getOutputStream()方法获得输出流
③按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息。(但不能读取自己放入线路的信息),通过输出流将信息写入线程
④关闭 Socket:断开客户端到服务器的连接,释放线路
(2) 服务器端
①调用ServerSocket(int port) :创建一个服务器端套接字并绑定到指定端口上,用于监听客户端的请求。
②调用 accept( ):监听连接请求,如果客户端请求连接则接受连接,返回通信套接字对象。
③调用该Socket类对象的 getOutputStream() 和getInputStream ():获取输出流和输入流,开始网络数据的发送和接收。
④关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。
- 代码示例
//实现从客户端发送一个图片,通过服务器端接收
//此代码客户端、服务器端都是本地主机
//客户端
@Test
public void client() throws IOException
{
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");// 指明要访问的IP地址(此处是本地IP)
Socket socket = new Socket(inetAddress, 9499); //1.创建套接字
OutputStream os = socket.getOutputStream();//2.调用方法得到输出流
//3.从本地读取文件并通过os输出流写出
FileInputStream fis = new FileInputStream(new File("C:\\Users\\mwz\\Desktop\\pic.png"));
byte[] buf=new byte[10];
int len;
while((len=fis.read(buf))!=-1)
os.write(buf,0,len);
// 4.关闭资源
fis.close();
os.close();
socket.close();
}
//服务器端
@Test
public void server() throws IOException
{
ServerSocket ss = new ServerSocket(9499);//1.创建一个服务器端套接字并绑定到指定端口上
Socket socket = ss.accept(); //2.调用accept() 监听连接请求
InputStream is = socket.getInputStream(); //3. 获取输入流
//通过输入流接收文件并保存在本地
FileOutputStream fos= new FileOutputStream(new File("C:\\Users\\mwz\\Desktop\\copypic.png"));
byte[]buf=new byte[10];
int len;
while((len=is.read(buf))!=-1)
fos.write(buf,0,len);
//4.关闭资源
fos.close();
is.close();
socket.close();
ss.close();
}
5. 基于Socket的UDP网络编程
- 类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序
- UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达
- DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号
- UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接( 无连接传输 )。
// 发送端
@Test
public void sender() throws IOException
{
InetAddress inet = InetAddress.getByName("127.0.0.1");
DatagramSocket socket = new DatagramSocket();
String str = "HelloWorld";
byte[] data = str.getBytes();
DatagramPacket packet = new DatagramPacket(data, 0, data.length, inet, 9699);
socket.send(packet);
socket.close();
}
// 接收端
@Test
public void receiver() throws IOException
{
DatagramSocket socket = new DatagramSocket(9699);
byte[] buffer = new byte[100];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);
System.out.println(new String(packet.getData(), 0, packet.getLength()));
socket.close();
}