在说明基于 TCP/IP 协议的网络编程之前,先来了解一下 Socket(网络套接字):
- 利用套接字(Socket)开发网络应用程序早已被广泛的采用,以至于成为事实上的标准
- 通信的两端都要有 Socket,是两台机器间通信的端点(API 原话)
- 网络通信其实就是 Socket 间的通信
- Socket 允许程序把网络连接当成一个流,数据在两个 Socket 间通过 IO 传输
- 一般主动发起通信的应用程序属客户端,等待通信请求的为服务端
网络编程某种程度上可以称作“Socket 编程”
TCP/IP 编程,简单模拟客户端与服务端之间的交互(先开 Server 再开 Client):
public class TestTCP {
@Test
public void client() {
Socket socket = null;
OutputStream os = null;
try {
// 创建 Socket 对象以指明目标 Server 的 IP 和端口
socket = new Socket("127.0.0.1", 9876);
// 调用该套接字对象的 getOutputStream()方法返回 OutputStream 对象以写出数据
os = socket.getOutputStream();
// 后面实际就是 IO 流的应用
os.write("This is the message sent by client".getBytes());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// socket 也是稀有资源,记得及时关闭
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void server() {
ServerSocket ss = null;
Socket socket = null;
InputStream is = null;
try {
// 创建 ServerSocket 对象指明开放那个端口作为传输端口
ss = new ServerSocket(9876);
// 调用 accept()方法,返回一个 Socket 对象,监听 ServerSocket 对应的端口并且接受对该端口的连接
socket = ss.accept();
// 调用该套接字对象的 getInputStream()方法返回 InputStream 对象以写入从 client 接收到的数据
is = socket.getInputStream();
// 后面实际就是 IO 流的应用
byte[] b = new byte[10];
int len;
while ((len = is.read(b)) != -1) {
// 打印字节流
System.out.print(new String(b, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
若要实现多步交互,注意 Socket 方法的阻塞性问题,如果一直监听端口,就不能执行后续代码,故记得调用相关 shutdown 方法以关闭监听,以下例子修改自上例,实现在 Server 端收到字节流后,返回给 Client 一条反馈信息:
public class TestTCP {
@Test
public void client() {
Socket socket = null;
OutputStream os = null;
InputStream is = null;
try {
// 创建 Socket 对象以指明目标 Server 的 IP 和端口
socket = new Socket("127.0.0.1", 9876);
// 调用该套接字对象的 getOutputStream()方法返回 OutputStream 对象以写出数据
os = socket.getOutputStream();
// 后面实际就是 IO 流的应用
os.write("This is the message sent by client".getBytes());
// ----------update----------
// 显式的禁用此套接字的输出流
socket.shutdownOutput();
// 接受反馈
is = socket.getInputStream();
byte[] b = new byte[10];
int len;
while ((len = is.read(b)) != -1) {
System.out.print(new String(b, 0, len));
}
// ----------update----------
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// socket 也是稀有资源,记得及时关闭
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void server() {
ServerSocket ss = null;
Socket socket = null;
InputStream is = null;
OutputStream os = null;
try {
// 创建 ServerSocket 对象指明开放那个端口作为传输端口
ss = new ServerSocket(9876);
// 调用 accept()方法,返回一个 Socket 对象,监听 ServerSocket 对应的端口并且接受对该端口的连接
socket = ss.accept();
// 调用该套接字对象的 getInputStream()方法返回 InputStream 对象以写入从 client 接收到的数据
is = socket.getInputStream();
// 后面实际就是 IO 流的应用
byte[] b = new byte[10];
int len;
while ((len = is.read(b)) != -1) {
// 打印字节流
System.out.print(new String(b, 0, len));
}
// ----------update----------
// 反馈一条消息给 Client
os = socket.getOutputStream();
os.write("I have received your message".getBytes());
// ----------update----------
} catch (IOException e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
时间: 2024-10-10 08:00:30