初步尝试了解下socket编程,结果被一个问题困扰了一天,回想真是失败~总结原因
1 明显的java功底太弱,对各种类的了解不彻底深入
2 解决问题的方法不够理性,系统~
陈述问题,最简单的情况,单线程交互,问题代码如下:
server:
client:
就这样一个问题困扰了我一天,虽然最终发现了问题所在,也可以解决问题,但是理解上还没有透彻。
依然的困惑:
1 流的传输中flush的机制到底是怎样的,为什么显示的调用flush()都没有效果,又为什么放弃了客户段接收信息,程序结束时,消息最终还是传向了服务端?
2 socket的内部机制,在javaeye看帖时看到一句话,算是识记了这个知识,但不理解
“[color=darkred]Socket的发送与接收是需要同步进行的,即客户端发送一条信息,服务器必需先接收这条信息, 而后才可以向客户端发送信息,否则将会有运行时出错。[/color] ”
感叹一些自己的java如此单薄~
[size=large][size=medium][color=darkred]今天又看了一些资料,发现以上理解全部错了~ 阻塞的真正原因是因为 readline()一直在寻找 换行符号"\n",而根本就不是flush的原因![/color][/size][/size]
1 明显的java功底太弱,对各种类的了解不彻底深入
2 解决问题的方法不够理性,系统~
陈述问题,最简单的情况,单线程交互,问题代码如下:
server:
package sl.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class BugServer {
public static void main(String[] args) {
ServerSocket ss = null;
try {
ss = new ServerSocket(10000);
System.out.println("server start...");
while(true){
Socket socket = ss.accept();
System.out.println("a client come in :"+socket.toString());
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//注意:if true, the println, printf, or format methods will flush the output buffer
//即使autoflush了,也只对三个方法有效!
PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
//若客户段没有使用autoflush方法,服务段将阻塞在这一行
System.out.println(in.readLine());
//问题出在这里,调用的不是autoflush的方法,即使后面有 pw.flush() 也不行!
pw.println("服务端反馈! to "+ socket.toString());
pw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
client:
package sl.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class BugClient {
Socket soc;
public static void main(String[] args){
new BugClient().send();
}
private void send() {
try {
soc = new Socket("127.0.0.1",10000);
PrintWriter socOut = new PrintWriter(soc.getOutputStream(),true);
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
BufferedReader netIn = new BufferedReader(new InputStreamReader(soc.getInputStream()));
String line = in.readLine();
System.out.println("input: "+line);
// 若使用了非 autoflush方式,即使显示flush的话,更是连服务端都收不到消息!
//由于消息没有"立即"传输到服务端, 会使得server在 阻塞在 in.readline()那一行.
socOut.print(line);
socOut.flush();
//若将此行注释掉,即客户段放弃接收服务段消息,
//那么这个客户段程序可以跑完,服务端将接收到消息,造成 socOut.flush()好像立即起了作用的假像
//实际上,并不是 flush()那行代码起了作用,而是程序结束时,对 out流做清理工作,使得消息最终发送了过去
/**
* 启用一下两行代码,由于 服务段已经被阻塞了,更别说响应,则客户段将阻塞在 netIn.readline();
*/
System.out.println(netIn.readLine());
soc.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
就这样一个问题困扰了我一天,虽然最终发现了问题所在,也可以解决问题,但是理解上还没有透彻。
依然的困惑:
1 流的传输中flush的机制到底是怎样的,为什么显示的调用flush()都没有效果,又为什么放弃了客户段接收信息,程序结束时,消息最终还是传向了服务端?
2 socket的内部机制,在javaeye看帖时看到一句话,算是识记了这个知识,但不理解
“[color=darkred]Socket的发送与接收是需要同步进行的,即客户端发送一条信息,服务器必需先接收这条信息, 而后才可以向客户端发送信息,否则将会有运行时出错。[/color] ”
感叹一些自己的java如此单薄~
[size=large][size=medium][color=darkred]今天又看了一些资料,发现以上理解全部错了~ 阻塞的真正原因是因为 readline()一直在寻找 换行符号"\n",而根本就不是flush的原因![/color][/size][/size]