目录
- Socket编程模型
- 使用网络IO流传输数据
1 Socket编程模型
Socket是一个类,叫“套接字”,用来在两个程序之间传输数据。
使用Socket编程模型的一般步骤:
第一步,在服务器程序中启动监听程序,即一个ServerSocket对象,这个程序可以监听来自其他程序的连接请求,设定服务器程序的端口号作为该ServerSocket对象的构造方法的参数;
第二步,在客户端程序中创建一个Socket对象,用于与服务器程序建立通信,将服务器程序的IP地址和端口号作为这个Socket对象的构造方法的参数;
第三步,在服务器程序中调用ServerSocket对象的accept方法,接收监听到的请求,并返回一个Socket对象,这个对象将保存客户端程序的IP地址和端口号;
第四步,先后启动服务器程序和客户端程序,存在一对Socket对象,通过从Socket对象上获取到传输IO流进行数据传输。
下面使用Java语言在两个程序之间建立连接。
// AServer.java
import java.io.IOException;
import java.net.ServerSocket;
public class AServer {
public static void main(String[] args) throws IOException {
// 启动监听程序
ServerSocket s = new ServerSocket(56789);
// 接收连接请求
s.accept();
System.out.println("A连接成功");
}
}
// BClient.java
import java.io.IOException;
import java.net.Socket;
public class BClient {
public static void main(String[] args) throws IOException {
// 在客户端程序创建Socket对象
new Socket("127.0.0.1", 56789);
System.out.println("B连接成功");
}
}
先后启动A和B,运行结果
程序 AServer:
A连接成功
程序 BClient:
B连接成功
然后,给两个程序都创建Socket对象。
public static void main(String[] args) throws IOException {
// 启动监听程序
ServerSocket s = new ServerSocket(56789);
System.out.println(s.getLocalPort());
System.out.println(s.getInetAddress());
System.out.println(s.getLocalSocketAddress());
// 接收连接
Socket socketA = s.accept();
System.out.println(s.getLocalPort());
System.out.println(s.getInetAddress());
System.out.println(s.getLocalSocketAddress());
System.out.println(socketA.getPort());
System.out.println(socketA.getLocalPort());
System.out.println(socketA.getInetAddress());
System.out.println(socketA.getLocalAddress());
System.out.println(socketA.getLocalSocketAddress());
}
public static void main(String[] args) throws IOException {
// 在客户端程序创建Socket对象
Socket socketB = new Socket("127.0.0.1", 56789);
System.out.println(socketB.getPort());
System.out.println(socketB.getLocalPort());
System.out.println(socketB.getInetAddress());
System.out.println(socketB.getLocalAddress());
System.out.println(socketB.getLocalSocketAddress());
}
先启动A,运行结果
56789
0.0.0.0/0.0.0.0
0.0.0.0/0.0.0.0:56789
再启动B,运行结果
程序 AServer:
56789
0.0.0.0/0.0.0.0
0.0.0.0/0.0.0.0:56789
56789
0.0.0.0/0.0.0.0
0.0.0.0/0.0.0.0:56789
53443
56789
/127.0.0.1
/127.0.0.1
/127.0.0.1:56789
程序 BClient:
56789
53443
/127.0.0.1
/127.0.0.1
/127.0.0.1:53443
可以分析出代码执行的过程,两个程序的IP地址和端口号,以及这些方法返回了什么。
2 使用网络IO流传输数据
涉及到两个类:
InputStream,输入流,用于程序接收数据
OutputStream,输出流,用于程序发送数据
具体操作如下:
在发送端创建OutputStream对象。使用socketB的getOutputStream方法返回一个OutputStream对象。
在发送端使用OutputStream对象的write方法发送数据。将要发送的数据拆分成一个个字节,形成一个个不大于256的int作为write方法的参数,即可发送。
在接收端创建InputStream对象。使用socketB的getInputStream方法返回一个InputStream对象。
在接收端使用InputStream对象的read方法接收数据。依次接受发送方发来的一个个字节,然后拼接成一串完整的数据。
下面先演示发送一个字节的数据。
public static void main(String[] args) {
try {
ServerSocket s = new ServerSocket(56789);
Socket socketA = s.accept();
OutputStream os = socketA.getOutputStream();
os.write(20);
// 强制立即发送
os.flush();
// 关闭进程占用的资源
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
try {
Socket socketB = new Socket("127.0.0.1",56789);
InputStream is = socketB.getInputStream();
int msg = is.read();
System.out.println(msg);
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
先后启动A和B,运行结果
程序 BClient:
20
如果要发送大于256的整数,代码如下。(例如1234567)
public static void main(String[] args) {
try {
ServerSocket s = new ServerSocket(56789);
Socket socketA = s.accept();
OutputStream os = socketA.getOutputStream();
// aka 10010(18) 11010110(214) 10000111(135)
int msg = 1234567;
int msg1 = (msg >> 16) & 255;
int msg2 = (msg >> 8) & 255;
int msg3 = msg & 255;
os.write(msg1);
os.write(msg2);
os.write(msg3);
os.flush();
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
try {
Socket socketB = new Socket("127.0.0.1", 56789);
InputStream is = socketB.getInputStream();
int msg1 = is.read();
int msg2 = is.read();
int msg3 = is.read();
int msg = msg1 << 16 | msg2 << 8 | msg3;
System.out.println(msg1);
System.out.println(msg2);
System.out.println(msg3);
System.out.println(msg);
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
先后启动A和B,运行结果
程序 BClient:
18
214
135
1234567