简单的客户端服务端通信
1 TCP/IP 编程练习
1.1 基于TCP的Socket通信
- Java语言的基于套接字编程分为服务端编程和客户端编程,其通信模型如图所示:
- 客户端Socket的工作过程包含以下四个基本步骤:
- 创建Socket:根据指定服务端的IP地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常,创建的同时会自动向服务器发起连接。
- 打开连接到Socket的输入/出流:使用
getInputStream()
/getOutputStream()
方法获得输入/出流 - 按照一定的协议对 Socket 进行读/写操作
- 关闭 Socket
- 服务器程序的工作过程包含以下四个基本步骤:
- 调用 ServerSocket(int port): 创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。
- 调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。
- 调用该 Socket 类对象的
getOutputStream()
和getInputStream()
:获取输出/入流,开始网络数据的发送和接收 - 关闭ServerSocket 和 Socket 对象:客户端访问结束,关闭通信套接字
ServerSocket 和 Socket
ServerSocket 对象负责等待客户端请求建立套接字连接,类似于邮局某个窗口中的业务员。即,服务器必须事先建立一个等待客户端请求建立套接字连接的 ServerSocket 对象。所谓接受客户的套接字请求,就是accept()
方法返回的一个 Socket 对象
1.2 例题1:客户端向服务器发送一段话
package NetDev;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class ClientAndServers {
public static void main(String[] args) {
// 先启动服务器,然后客户端进行接入
new Thread() {
@Override
public void run() {
Servers();
}
}.start();
Client();
}
public static void Client() {
Socket socket = null;
OutputStream os = null;
try {
InetAddress inet = InetAddress.getByName("127.0.0.1");
socket = new Socket(inet, 8859);
os = socket.getOutputStream();
os.write("你好啊,我是客户端".getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
socket.close();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void Servers() {
ServerSocket ss = null;
Socket accept = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
// 创建服务器端的ServerSocket,指明自己的端口号
ss = new ServerSocket(8859);
// 调用accept()方法,表示接收来自于客户端的Socket
accept = ss.accept();
// 获取输入流
is = accept.getInputStream();
// 读取输入流中的数据
byte[] buf = new byte[20];
int len = 0;
baos = new ByteArrayOutputStream();
while ((len = is.read(buf)) != -1) {
baos.write(buf, 0, len);
}
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
baos.close();
is.close();
accept.close();
ss.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
1.3 例题2:客户端向服务器发送文件
package NetDev;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 客户端向服务器上传文件
*
* @author Yorick
*
*/
public class ClientAndServers_File {
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
Servers();
}
}.start();
Client();
}
public static void Client() {
InetAddress inet = null;
Socket socket = null;
OutputStream outputStream = null;
FileInputStream fileInputStream = null;
try {
inet = InetAddress.getByName("127.0.0.1");
socket = new Socket(inet, 8899);
// 获取输出流,从客户端将数据发送到服务端的流
outputStream = socket.getOutputStream();
// 获取文件流,将文件以流的方式从本地读取到向服务端发送的流中
fileInputStream = new FileInputStream(new File("C:\\Users\\Yorick\\Desktop\\Head.jpg"));
// 读取文件
byte[] buffer = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(buffer)) != -1) {
outputStream.write(buffer);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
socket.close();
outputStream.close();
fileInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void Servers() {
ServerSocket serverSocket = null;
Socket accept = null;
InputStream inputStream = null;
FileOutputStream fileOutputStream = null;
try {
serverSocket = new ServerSocket(8899);
// 可以接收客户端发送的信息
accept = serverSocket.accept();
// 获取客户端发来的流
inputStream = accept.getInputStream();
// 将客户端发来的流中的信息写入文件中
fileOutputStream = new FileOutputStream(new File("C:\\Users\\Yorick\\Desktop\\Head_Server.jpg"));
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
accept.close();
inputStream.close();
fileOutputStream.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
2 UDP 编程练习
2.1 基于 UDP 的Socket通信
- 类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序
- UDP 数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证 UDP 数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
- DatagramPacket 对象封装了 UDP 数据报,在数据报中包含了发送端的 IP 地址和端口号,以及接收端的 IP 地址和端口号
- UDP 协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接受方的连接。如同发快递包裹一样。
- UDP 网络通信的流程
- DatagramSocket 和 DatagramPacket
- 建立发送端,接收端(发送端和接收端是两个独立的运行程序)
- 建立数据包
- 调用 Socket 的发送、接收方法
- 关闭 Socket
2.2 例题1:发送数据到服务器
package NetDev;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDP_SenderAndReceiver {
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
Receiver();
}
}.start();
Sender();
}
public static void Sender() {
DatagramSocket datagramSocket = null;
DatagramPacket datagramPacket = null;
try {
// 创建 DatagramSocket 对象,建立连接
datagramSocket = new DatagramSocket();
// 将数据封装到 DatagramPacket 对象中(包括数据,发送地址 --IP,端口号)
byte[] data = "发送端发送".getBytes();
InetAddress localHost = InetAddress.getLocalHost();
datagramPacket = new DatagramPacket(data, 0, data.length, localHost, 9898);
// 发送数据
datagramSocket.send(datagramPacket);
} catch (Exception e) {
e.printStackTrace();
} finally {
datagramSocket.close();
}
}
public static void Receiver() {
DatagramPacket datagramPacket = null;
DatagramSocket datagramSocket = null;
try {
// 创建 DatagramSocket 对象,并指定端口号
datagramSocket = new DatagramSocket(9898);
// 创建 DatagramPacket 对象
byte[] data = new byte[100];
datagramPacket = new DatagramPacket(data,0,data.length);
// 接收数据
datagramSocket.receive(datagramPacket);
// 输出数据
System.out.println(new String (datagramPacket.getData(),0,datagramPacket.getLength()));
} catch (Exception e) {
e.printStackTrace();
} finally {
datagramSocket.close();
}
}
}
3 URL 编程
3.1 解析URL
package NetDev;
import java.net.MalformedURLException;
import java.net.URL;
public class URL_Test {
public static void main(String[] args) {
try {
URL url = new URL("https://editor.csdn.net/md?articleId=108099857");
System.out.println("协议名:" + url.getProtocol());
System.out.println("主机名:" + url.getHost());
System.out.println("端口号:" + url.getPort());
System.out.println("文件路径:" + url.getPath());
System.out.println("文件名:" + url.getFile());
System.out.println("查询名:" + url.getQuery());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
// 运行结果
// 协议名:https
// 主机名:editor.csdn.net
// 端口号:-1
// 文件路径:/md
// 文件名:/md?articleId=108099857
// 查询名:articleId=108099857
3.2 从 Tomcat 服务器上下载图片
public static void DownloadPic() {
URL url = null;
HttpURLConnection openConnection = null;
InputStream inputStream = null;
FileOutputStream fileOutputStream = null;
try {
// 指定连接
url = new URL("http://localhost:8080/examples/Collection.jpg");
// 获取连接
openConnection = (HttpURLConnection) url.openConnection();
// 打开连接
openConnection.connect();
// 获取输入流
inputStream = openConnection.getInputStream();
// 输出到本地文件中完成下载
fileOutputStream = new FileOutputStream(new File("C:\\Users\\Yorick_PC\\Desktop\\Test\\Collection.jpg"));
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (openConnection != null) {
// 关闭URL的连接
openConnection.disconnect();
}
}
}