笛子的Java系列总结——网络编程
一、通信要素1:IP和端口号
1、计算机网络相关基础知识介绍
暂时省略,以后会进行专门的总结来补充链接
2、InetAddress类
- Internet上的主机有两种方式表示地址:
- 域名(hostName):www.baidu.com
- IP地址(hostAddress):
- InetAddress类主要表示IP地址,两个子类:Inet4Address、Inet6Address
- InetAddress 类没有提供公共的构造器,而是提供了如下几个静态方法来获取InetAddress 实例:
- public static InetAddress getLocalHost()
- public static InetAddress getByName(String host)
- InetAddress提供了如下几个常用的方法:
- public String getHostAddress() :返回 IP 地址字符串(以文本表现形式)
- public String getHostName() :获取此 IP 地址的主机名
- public byte[] getAddress() :以byte数组形式返回IP地址
- public boolean isReachable(int timeout) :测试是否可以达到该地址
3、InetAddress类代码测试
public class InetAdress {
@Test
public void test1() throws UnknownHostException {
InetAddress address_1 = InetAddress.getByName("www.baidu.com");
System.out.println(address_1);
System.out.println(address_1.getHostName()); // HostName 域名
System.out.println(address_1.getHostAddress()); // IP地址
byte[] temp = address_1.getAddress(); // byte数组存储的IP地址
for(byte b : temp) {
System.out.print(b + " ");
}
System.out.println();
InetAddress address_2 = InetAddress.getLocalHost(); // 获取本机域名和IP地址
System.out.println(address_2);
}
}
二、通信要素2:网络协议
1、计算机网络协议理论知识介绍
TCP/IP体系相关内容,暂时省略,以后会进行专门的总结
2、Socket
- 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字
- 通信的两端都要有Socket,是两台机器通信间的端点,网络通信其实就是Socket间的通信,Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输
- Socket分类:
- 流套接字(stream socket):使用TCP提供可依赖的字节流服务
- 数据报套接字(datagram socket):使用UDP提供“尽力而为”的数据报服务
三、TCP网络编程
1、客户端Socket工作过程的四个基本步骤
- 创建Socket
通过指定服务器的IP地址/域名 + 端口号构建Socket类对象,若服务器响应,则建立客户端到服务器的通信线路,若连接失败,会出现异常。 - 打开连接到Socket的输入/输出流
使用getInputStream()方法获取输入流,使用getOutputStream方法获取输出流 - 按照一定的协议对Socket进行读/写操作
通过读入流读取服务器放入线路的信息,通过输出流将自己的信息写入线路 - 关闭Socket
断开客户端到服务器的连接,释放线路
2、服务器端ServerSocket工作过程的四个步骤
- 创建Server Socket
指定要监听的窗口,使用ServerSocket(int port)创建 - 调用accept()表示接收来自于客户端的socket
- 调用该Socket类对象的getOutputStream() 和 getInputStream ()
获取输出流和输入流,开始网络数据的发送和接收 - 关闭ServerSocket 和Socket 对象
客户端访问结束,关闭通信套接字
3、客户端与服务器端TCP通信代码测试
import org.junit.Test;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPTest {
@Test
public void client() throws IOException {
Socket socket = new Socket("127.0.0.1",5555);
OutputStream out= socket.getOutputStream();
InputStream in = socket.getInputStream();
FileInputStream fis = new FileInputStream("F:\\wubo\\JavaCode\\JavaSenior2\\day07\\test1.jpg");
byte[] tmp = new byte[1024];
int len = 1;
while((len = fis.read(tmp)) != -1) {
out.write(tmp);
}
System.out.println("客户端自己的提示:客户端已将图片传输过去");
socket.shutdownOutput(); // 这条如果没有的话服务端无法判断什么时候客户端的数据传输完毕导致无法正常关闭
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] tmp2 = new byte[20];
while((len = in.read(tmp2)) != -1) {
baos.write(tmp2);
}
System.out.println("来自服务器端的提示:" + baos.toString());
baos.close();
in.close();
out.close();
socket.close();
}
@Test
public void server() throws IOException {
ServerSocket sever = new ServerSocket(5555);
Socket ss = sever.accept();
InputStream in = ss.getInputStream();
OutputStream out = ss.getOutputStream();
FileOutputStream fos = new FileOutputStream("C:\\Users\\User\\Desktop\\copy.jpg");
byte[] tmp = new byte[1024];
int len = 1;
while((len = in.read(tmp)) != -1) {
fos.write(tmp);
}
System.out.println("服务器端自己的提示:服务端已收到并复制成功");
out.write("服务器端照片已收到,非常nice".getBytes());
fos.close();
in.close();
out.close();
ss.close();
sever.close();
}
}
客户端输出
服务器端输出
四、UDP网络编程
- 代码实现方面不同于TCP的地方有
- 数据不是直接传递和读取,而是需要使用DatapramPacket类的对象进行封装和拆封
- 因为UDP不保证通信的可靠性,没有正式传输数据前三次握手的过程,所以即使服务器端未启动,客户端程序也不会报错
1、客户端Socket工作过程的四个基本步骤
- 使用DatagramSocket类建立客户端套接字
- 使用DatagramPacket类对要发送的数据进行封装,并指定目的地址和端口号
- 使用send()发送数据DatagramPacket封装后的数据
- 数据传输结束后关闭客户端
2、客户端Socket工作过程的五个基本步骤
- 使用DatagramSocket类建立服务器端套接字,指明要监听的端口号
- 定义要用来接收客户端数据的DatagramPacket类对象
- 使用receive()接收数据存入2中定义的对象
- 使用getData()获取实际数据内容
- 数据传输结束后关闭服务器端
3、客户端和服务器端UDP通信代码测试
import org.junit.Test;
import java.io.IOException;
import java.net.*;
public class UDPTest {
@Test
public void client() throws IOException {
// 1. 使用DatagramSocket类建立客户端套接字
DatagramSocket socketClient = new DatagramSocket();
String s = "旅途总有一天会迎来终点,不必匆忙";
byte[] data = s.getBytes();
// 2. 使用DatagramPacket类对要发送的数据进行封装,并指定目的地址和端口号
DatagramPacket sendData = new DatagramPacket(data,0,data.length,InetAddress.getLocalHost(),6666);
// 3. 使用send()发送数据DatagramPacket封装后的数据
socketClient.send(sendData);
// 4. 数据传输结束后关闭客户端
socketClient.close();
}
@Test
public void server() throws IOException {
// 1. 使用DatagramSocket类建立服务器端套接字,指明要监听的端口号
DatagramSocket socketServer = new DatagramSocket(6666);
byte[] buffer = new byte[200];
// 2. 定义要用来接收客户端数据的DatagramPacket类对象
DatagramPacket receiveData = new DatagramPacket(buffer,0,buffer.length);
// 3. 使用receive()接收数据存入2中定义的对象
socketServer.receive(receiveData);
// 4. 使用getData()获取实际数据内容
System.out.println(new String(receiveData.getData(),0,receiveData.getLength()));
// 5. 数据传输结束后关闭服务器端
socketServer.close();
}
}
五、URL网络编程
1、URL简介
- URL编程不同于上面两部分写客户端和服务端的程序,而是直接通过URL获取网络资源的编程
- URL(Uniform Resource Locator):统一资源定位符,它表示 Internet 上 某一资源的地址。
- URL的基本结构由5部分组成
< 传输协议>://< 主机名>:< 端口号>/< 文件名># 片段名? 参数列表
例如:http://192.168.1.100:8080/helloworld/index.jsp#a?username=shkstart&password=123
#片段名,即锚点,例如看小说,直接定位到章节
参数列表格式:参数名=参数值&参数名=参数值…
2、URL类构造器及常用方法
- 构造器
- public URL (String spec):通过一个表示URL地址的字符串可以构造一个URL对象
例如:URL url = new URL (“http://www.baidu.com/”);
- public URL(URL context, String spec):通过基 URL 和相对 URL 构造一个 URL 对象
例如:URL downloadUrl = new URL(url, “download.html");
- public URL(String protocol, String host, String file);
例如:new URL(“http”, “www.baidu.com”, “download. html");
- public URL(String protocol, String host, int port, String file);
例如: URL gamelan = new URL(“http”, “www.baidu.com”, 80, “download.html");
- URL类常用方法
一个URL对象生成后,其属性是不能被改变的,但可以通过它给定的
方法来获取这些属性:
import org.junit.Test;
import java.io.IOException;
import java.net.URL;
public class URLTest {
@Test
public void test2() throws IOException {
URL url = new URL("https://www.bilibili.com/video/BV1Kb411W75N?p=629&spm_id_from=pageDriver");
System.out.println("获取该URL的协议名 :" + url.getProtocol());
System.out.println("获取该URL的主机名 :" + url.getHost());
System.out.println("获取该URL的端口名: " + url.getPort());
System.out.println("获取该URL的文件路径: " + url.getPath());
System.out.println("获取该URL的文件名: " + url.getFile());
System.out.println("获取该URL的查询名: " + url.getQuery());
}
}
3、针对HTTP协议的URLConnection类
通过URL对象建立URLConnection对象,进而获取url连接的输入流和输出流,即可与现有的CGI程序进行交互
注:服务器端的 CGI (公共网关接口-Common Gateway
Interface-的简称,是用户浏览器和服务器端的应用程序进行连接的接口)
@Test
public void test3() throws IOException {
URL url = new URL("https://alifei05.cfp.cn/creative/vcg/veer/800water/veer-140775274.jpg");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
InputStream in = connection.getInputStream();
FileOutputStream fos = new FileOutputStream("F:\\wubo\\JavaCode\\JavaSenior2\\day07\\test2.jpg");
byte[] buffer = new byte[1024];
int len = 1;
while((len = in.read(buffer)) != -1) {
fos.write(buffer);
}
fos.close();
in.close();
connection.disconnect();
}