Socket通信学习系列
Socket网络编程学习基础
Socket通信学习实例一之TCP通信
Socket通信学习实例二之即时通信
Socket通信学习实例三之断点上传
Socket通信学习实例四之UDP通信
Socket通信学习实例五之模拟Http
Socket通信(通过TCP协议)
Socket服务端和客户端通信模型:
简单的说Socket之间通信的步骤是这样的:
- 建立服务端ServerSocket和客户端Socket
- 打开连接到Socket的输出输入流
- 按照协议进行读写操作
- 关闭相对应的资源
Socket通信时需要用到以下几个类:
- ServerSocket
用于在服务端指定端口建立一个监听服务 - Socket
用于服务器端与客户端之间相互通信 - InputStream OutputStream
处理字节流的抽象类,字节流的所有类的超类 - InputStreamReader OutputStreamWriter
处理字符流的抽象类,字节流与字符流转换的桥梁 - BufferedReader BufferedWriter
BufferedReader 由Reader类扩展而来,提供通用的缓冲方式文本读取,readLine读取一个文本行,
从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取
BufferedWriter 由Writer 类扩展而来,提供通用的缓冲方式文本写入, newLine使用平台自己的行分隔符,
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入 - PrintWriter
与BufferedWriter类似,不过PrintWriter提供println()方法可以写不同平台的换行符,而BufferedWriter可以任意设定缓冲大小
Socket通信有一个前提就是需要有唯一的标示进程,而进程可以利用ip地址+协议+端口号来组成,因此我们首先需要知道服务端的ip地址,客户端才能与服务端进行连接
获取ip地址需要这两个类
- InetAddress
InetAddress是Java对IP地址的封装. - NetworkInterface
NetworkInterface类可以得到本机所有的物理网络接口和虚拟机等软件利用本机的物理网络接口创建的逻辑网络接口的信息
使用InetAddress配合NetworkInterface使用来获取本地ip地址代码:
public static String getIP() {
String ip = null;
try {
Enumeration en = NetworkInterface.getNetworkInterfaces();
while (en.hasMoreElements()) {
NetworkInterface ni = (NetworkInterface) en.nextElement();
if (ni.isVirtual() || "virbr0".equals(ni.getName())) {
continue;
}
Enumeration<InetAddress> ee = ni.getInetAddresses();
while (ee.hasMoreElements()) {
InetAddress ia = ee.nextElement();
if (!ia.isLoopbackAddress() &&
!(ia instanceof Inet6Address)
) {
ip = ia.getHostAddress();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return ip;
}
主要思路是通过NetworkInterface获得所有网络接口的信息然后通过遍历赋值给InetAddress类找到真实网卡的ip地址
然后我们来看个服务端与客户端建立Socket连接的实例:
服务端主要代码
public SocketTest() throws IOException {
//1.创建一个服务端Socket,即ServerSocket,指定绑定的端口,并监听此端口
ServerSocket serverSocket = new ServerSocket(SocketTool.PORT);
String ip = SocketTool.getIP();
System.out.println("1.服务端已就绪,等待客户端接入,服务端ip地址: " + ip);
//2.调用accept()等待客户端连接,建立连接后,accept()返回一个最近创建的Socket对象,
//该Socket对象绑定了客户程序的IP地址或端口号
Socket socket = serverSocket.accept();
//3.连接后获取输入流,读取客户端信息
InputStream is= socket.getInputStream(); //获取输入流
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String info;
while ((info = br.readLine()) != null) {//循环读取客户端的信息
System.out.println("3.服务端接收客户端信息: " + info);
}
socket.shutdownInput();//关闭输入流
//4.服务端收到客户端消息后返回一条消息
OutputStream os = socket.getOutputStream();//字节输出流
PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流
pw.write("服务端 " + ip + " 返回消息!");
pw.flush();
System.out.println("4.服务端返回信息给客户端: " + "服务端 " + ip + " 返回消息!");
//socket.shutdownOutput();//关闭输出流
socket.close();
}
服务端监听端口,等待有客户端连接后,读取输入流获得客户端发送的信息,然后返回一条信息给客户端,发送后关闭连接
客户端主要代码
private void acceptServer() throws IOException {
//1.创建客户端Socket,指定服务器地址和端口
//Log.i(TAG, "客户端:before socket");
Socket socket = new Socket(SocketTool.HOST, SocketTool.PORT);
socket.setSoTimeout(5000);
//Log.i(TAG, "客户端:after socket");
//2.获取输出流,向服务器端发送信息
OutputStream os = socket.getOutputStream();//字节输出流
PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流
//获取客户端的IP地址
String ip = SocketTool.getIP();
//3.客户端发送消息
pw.write("客户端 " + ip + " 接入服务器!");
pw.flush();
Log.i(TAG, "2.客户端发送信息: 客户端 " + ip + " 接入服务器!");
socket.shutdownOutput();//关闭输出流
//4.客户端等待服务端返回的消息
InputStream is = socket.getInputStream(); //获取输入流;
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String info;
while ((info = br.readLine()) != null) {//循环读取客户端的信息
Log.i(TAG, "5.客户端接收服务端信息: " + info);
}
//socket.shutdownInput();//关闭输入流
socket.close();
}
客户端在连接服务端成功后发送一条消息给服务端,然后等待服务端发送消息,收到后打印出来
完整示例:
SocketSamples