您的位置:首页 > 其它

记录 serverSocket socket 输入,输出流,关闭顺序,阻塞,PrintWriter的一些问题.

2017-02-28 10:09 447 查看
关于socket.getOutputStream() 的一些问题, OutputStream的flush是一个空方法,所以需要另一个实现了Flush的流来包装一下

这里为什么使用PrintWriter,而不使用BufferedWriter

原因是在接收方使用BufferedReader 的readLine,而BufferedWriter.write并不会自动换行,所以会导致读取阻塞,需要手动换行,代码如下:

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("你好啊");
//            因为在服务端使用的是readLine,所以如果不调用newLine,那么会一直阻塞
bw.newLine();
bw.flush();


以下两个测试类代码,在输出数据的时候,输出空行为结束符,在读取输入流的时候都在循环内判断了readLine长度是否为0(当然规范的做法是约定长度,根据长度判断是否结束),原因如下摘抄☞:点击这里

对于socket,不能认为把某次写入到流中的数据读取完了就算流结尾了,但是socket流还存在,还可以继续往里面写入数据然后再读取。所以用BufferedReader封装socket的输入流,调用BufferedReader的readLine方法是不会返回null的

所以在循环内如果不判断 msg!=null&&msg.length()>0 那么程序将会一直阻塞在这里(程序是因为readLine阻塞,并不是死循环)

关于流的关闭会影响socket的使用,而且对一次连接关闭流以后,没有办法再次打开,哪怕只关闭输入流,也会导致输出流不能使用.反之亦然.

所以如果在一次IO操作以后,还有另一次IO,那么就先不关闭.等全部用完再关闭.

ServerSocket

@RunWith(JUnit4.class)
public class ServerSocketTest {
@Test
public void testServer(){
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket();
//            serverSocket.setReuseAddress(true);
//            System.out.println(InetAddress.getLocalHost());//获取的本机地址不一定正确
serverSocket.bind(new InetSocketAddress(8000));

while(true){
//一旦连接,返回的socket包含客户端信息的socket
Socket socket = serverSocket.accept();
PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
pw.println("host:"+socket.getInetAddress()+":"+socket.getPort()+"建立链接");
//这里发送空行作为结束符,当然规范做法是根据长度作为标识
pw.println("");
//因为new PrinWriter的时候指定了autoFlush的参数为true所以不用手动flush
//                pw.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
for(String msg = br.readLine();msg!=null&&msg.length()>0;msg = br.readLine()){
System.out.println(msg);
}
pw.close();
br.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

}


ClientSocket

/**
*
* @author lzw
*
*/
@RunWith(JUnit4.class)
public class SocketClient {
@Test
public void testClient() throws UnknownHostException, IOException{
//表示连接到服务器的 地址以及端口
SocketAddress address = new InetSocketAddress("19.95.103.112",8000);
Socket socket = new Socket();
socket.connect(address,60000);//连接
//读取服务端返回的数据
getMsb(socket);
sendMsg(socket);
socket.close();
}

private void sendMsg(Socket socket){
PrintWriter pw = null;
//        BufferedWriter bw = null;
try {

//            bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//            bw.write("你好啊");
//因为在服务端使用的是readLine,所以如果不调用newLine,那么会一直阻塞
//            bw.newLine();
//            bw.flush();
//            OutputStream os =  socket.getOutputStream();
//            //这个是一个空方法
//            os.flush();
pw = new PrintWriter(socket.getOutputStream(),true);
pw.println("你好啊");
       //输出空行作为结束标识
       pw.println("");
//因为new PrinWriter的时候指定了autoFlush的参数为true所以不用手动flush
//            pw.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
//因为本次连接,到这个方法以后没有更多交互,所以可以关闭
if(pw!=null){
pw.close();
}
}
}

private void getMsb(Socket socket){
InputStream is = null;
BufferedReader br = null;
try {
is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
for(String msg = br.readLine();msg!=null&&msg.length()>0;msg = br.readLine()){
System.out.println(msg+"--");
}
} catch (IOException e) {
e.printStackTrace();
}finally{
//这里不能关闭流,否则会把socket也关闭了(因为后面还要发送数据,所以不能关闭流,不管是关闭输入输入其中之一,都会导致输入和输出都不能使用)
//                try {
//                    if(br!=null)
//                        br.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: