[size=medium]
[b]日日行,不怕千万里;常常做,不怕千万事。[/b]
意思是说,每天都走路的话,就不怕走千里万里,每天都做事的话,就不怕做了千事万事。学习也一样,每天学一点,就不怕学习了千万知识。
上一次我们对Socket编程有了一个初步的了解,今天我们来继续学习。上一次我们写了一个简单的服务端和客户端程序,只是实现了客户端写,服务端读。今天我们来实现一个服务端和客户端同时读写的程序。
[b]需求:实现一个服务端和客户端同时读写。[/b]
为了便于大家更好的理解,我画了一个程序流程图,虽然不是很专业和美观,但旨在说明问题。
[b]1、程序流程图:[/b]
[img]http://dl2.iteye.com/upload/attachment/0095/9910/64ca9221-8c77-35b7-92fc-cad0b36523e3.jpg[/img]
[b]2、代码实现:[/b]
[b]1)服务端代码:[/b]
[/size]
/**
* 服务端
* 需求:服务端和客户端同时读写
* @author Sam
*
*/
public class EnhanceServer {
/**
* @param args
*/
public static void main(String[] args) {
try {
// 创建一个服务端ServerSocket,监听指定端口的请求
ServerSocket ss = new ServerSocket(9999);
System.out.println("Server 等待客户端接入...");
// 监听客户端请求
Socket socket = ss.accept();
// 与客户端建立连接之后,读取客户端发过来的信息
InputStream is = socket.getInputStream();
byte[] buffer = new byte[1024];
int len = 0;
// 定义一个字符串构建器,用于存储客户端发过来的数据
StringBuilder sBuilder = new StringBuilder();
int index;
while ( (len=is.read(buffer)) != -1 ) {
String temp = new String(buffer, 0, len);
// 读到结束符,则跳出循环
if ( (index=temp.indexOf("eof")) != -1 ) {
// 截取指定长度
sBuilder.append(temp.substring(0, index));
break;
}
// 如果没有读到结束符,则继续读取,并加入字符串构建器
sBuilder.append(temp);
}
System.out.println("Server 来自客户端的信息 : " + sBuilder.toString());
// 读完之后,往客户端发送响应数据
OutputStream out = socket.getOutputStream();
out.write("Hello Client!".getBytes());
out.write("eof".getBytes());// 写一个结束符
out.flush();
out.close();
is.close();
socket.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
[size=medium]
[b]服务端代码分析:[/b]
[b]1)代码流程:[/b]服务端先读取客户端发送过来的数据,然后输出在控制台中,读完之后,接着往客户端写一段回应数据。
前面我们提到服务端在监听客户端请求时,使用的accept方法是阻塞方法;
[b]2)问题原因:[/b]在这里while循环判断条件中的read方法也是阻塞式操作的,也就是说while循环判断条件中当读到数据时,就会执行循环体,否则就一直处于阻塞状态,这样后面的代码就永远无法执行了。
[b]3)解决方案:[/b]所以,我们通常都会约定一个结束标记,当服务端读到客户端发送过来的数据包含结束标记时,服务端就会跳出循环,接着执行往下的代码。
在这里我们约定结束标记为eof,每次写完数据都要写一个结束标记!
[b]2)客户端代码:[/b]
[/size]
/**
* 客户端
* @author Sam
*
*/
public class EnhanceClient {
/**
* @param args
*/
public static void main(String[] args) {
try {
// 与服务端建立连接(服务端主机号,服务端监听的端口号)
Socket socket = new Socket("127.0.0.1", 9999);
// 与服务端建立连接之后,就可以往服务端写数据
OutputStream out = socket.getOutputStream();
// 往服务端中写数据
out.write("Hello Server!".getBytes());
out.write("eof".getBytes());// 写一个结束符,表示写入完毕
out.flush();
// 写完之后,获取服务端的响应数据
InputStream is = socket.getInputStream();
byte[] buffer = new byte[1024];
int len = 0;
// 定义一个StringBuilder存储客户端发过来的数据
StringBuilder sBuilder = new StringBuilder();
int index;
while ( (len=is.read(buffer)) != -1 ) {
String temp = new String(buffer, 0, len);
// 读到结束符,则跳出循环
if ( (index=temp.indexOf("eof")) != -1) {
sBuilder.append(temp.substring(0, index));
break;
}
sBuilder.append(temp);
}
System.out.println("Client 来自服务端的信息 : " + sBuilder.toString());
out.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
[size=medium]
[b]客户端代码分析:[/b]
1)[b]代码流程:[/b]
客户端往服务端写一段数据,写完之后,接着读取服务端返回的响应数据,并输出在控制台中。
[b]2)问题原因:[/b]
同理,客户端发送数据完毕后,往流中写一个结束标记符告诉服务端数据已经发送完毕。
[b]3、运行结果:[/b]
注意:先运行Server程序,再运行Client程序。结果如下:
[b]1)Server程序控制台:[/b]
[img]http://dl2.iteye.com/upload/attachment/0095/9933/0f9e59ac-4cf6-313f-8f6e-74d59f160ac7.jpg[/img]
[b]2)Client程序控制台:[/b]
[img]http://dl2.iteye.com/upload/attachment/0095/9935/739f9e69-4ec3-394d-afef-d8ebcc6329dc.jpg[/img]
[b]4、总结:[/b]
这便是服务端和客户端同时通信的程序。客户端发送数据给服务端,服务端收到数据之后再返回相应的结果给客户端。
[/size]