(二)socket·IO 和 socket

版权声明:本文为博主原创文章,如有错误劳烦指正。转载请声明出处,便于读取最新内容。——Bestcxx https://blog.csdn.net/bestcxx/article/details/86710025

socket 的简单介绍
  • socket 属于网络分层中的应用层
  • socket 可以使用 TCP/IP 协议进行可靠传输,也可以使用 UDP 协议进行不可靠传输
  • If a UDP socket is used, TCP/IP related socket options will not apply.(如果使用 UDP,则TCP/IP 的功能将失效)
  • Use DatagramSocket instead for UDP transport.(使用DatagramSocket代替UDP传输。)
  • socket 是全双工通讯传输,即服务器端和客户端发送或者接受数据可以同步进行
提出两个问题
socket 中的等待

在 socket 的使用中不得不注意这种问题,服务端收到客户端的请求,开始接受数据,如果客户端没有给出数据结束的信号,那么理论上服务器端是不应该停止等待的,这样在单线程开发中,服务器端就会阻塞了。
假如我们期望客户端传递给服务器端之后也能得到服务器端的响应,这个问题就不得不解决。

readLine的阻塞

在上一篇文章(BufferedReader.readLine)中我们提到了这个问题,readLine 本身是一个阻塞的方法,除非遇到了换行符,再加之服务器端一般会使用死循环来调用这个方法,所以当客户端没有给出传输结束的信号时,这个环节也会造成阻塞。
假如我们期望客户端传递给服务器端之后也能得到服务器端的响应,这个问题就不得不解决。

解决方案之 socket 和 IO 的技巧

上面的问题其实可以分为两类,一类是客户端只会和服务器端交互一次,即一次发送一次接收;一类是客户端和服务器端存在多次穿插交互,即多次穿插的发送和接收
所以关键在于,客户端给服务器端以信号,让其感知到一次发送结束,然后根据客户端是否要再次发送数据来决定客户端采取的具体措施

  • 技巧点如下:
    1、 如果客户端和服务端只有一次交互(相互只发送一次信息),可以调用客户端的 socket.shutdownOutput(); 方法,这样服务器端就可以知道客户端发送结束了不会再阻塞。
    但是注意不能用任何流的 close() 方法,那样 客户端socket 会关闭,就无法接受服务器端返回的信息了。
    2、对于如果是多交互可以在readline死循环里加一个判断,
    按行读到某一个特殊字符就可以中断循环,这样可以循环n次

    for(;(str=bufferedReader.readLine())!=null;){
         if("end".equals(str)){
             break;
         }
         System.out.print(str);
     }
    

    3、发送数据使用 PrintWriter.println(“内容”),这个方法内含 flush() 和 换行,可以立即发送缓冲区数据,并且防止服务器端使用 readLine() 方法时阻塞。注意 PrintWriter 需要调用构造方法 。PrintWriter printWriter=new PrintWriter(writer,true);否则需要手动调用 flush()发送缓存区的数据。
    4、在一个解决思路是使用多线程,既然读会阻塞,那么就另起一个线程进行写,socket 是全双工通讯传输的。
    5、一般而言,服务器端要使用线程池。

socket 服务端和客户端一次交互的例子

实现客户端访问服务端
客户端向服务端发送数据
服务端接受完数据后返回客户端数据
结束

服务端代码
import java.io.*;
import java.net.*;
import java.nio.charset.Charset;

/**
 * socket 简单例子 服务端
 * @Author: jie.wu
 */
public class Server {

    public static void main(String [] args){
        Server s=new Server();
        s.start();
        System.out.println("系统默认编码格式="+Charset.defaultCharset().name());
    }

    public void start(){
        //服务端声明
        ServerSocket serverSocket;
        //客户端请求声明
        Socket clientSocket;
        //客户端输入流声明
        InputStream inputStream=null;
        BufferedReader bufferedReader =null;
        //客户端输出流声明
        OutputStream outputStream=null;
        PrintWriter printWriter=null;
        try{
            //初始化服务端
            serverSocket=new ServerSocket(10000);
            //初始化客户端
            clientSocket=serverSocket.accept();
            //初始化客户端输入流
            inputStream=clientSocket.getInputStream();
            //读取客户端传输的内容
            //BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset().name()));
            //输出
            String str="";
            System.out.print("客户端输入:");
            //客户端没有发送结束服务端会阻塞,使用 readline 方法没有读到换行符会阻塞
            for(;(str=bufferedReader.readLine())!=null;){
                //和客户端约定输出结束的符号
                if("end".equals(str)){
                    break;
                }
                System.out.print(str);
            }
            System.out.println();
            /*
            char b[]=new char[8192];
            StringBuffer sbf=new StringBuffer();

            for(int n=0;(n=bufferedReader.read(b,0,n))!=-1;){
                sbf.append(b);
            }
            System.out.println(sbf.toString());
            */
            //初始化客户端输出流
            outputStream=clientSocket.getOutputStream();
            printWriter=new PrintWriter(new OutputStreamWriter(outputStream, Charset.defaultCharset().name()),true);
            printWriter.println("你好,我是服务器端");
            printWriter.println("end");

        }catch(Exception e){
            System.out.println("服务器报错"+e);
        }finally {
            try{
                if(inputStream!=null){inputStream.close();}
                if(bufferedReader!=null){bufferedReader.close();}
                if(outputStream!=null){ outputStream.close();}
                if(printWriter!=null){ printWriter.close();}
            }catch(Exception e){
                System.out.println("服务器真的报错了"+e);
            }
        }
    }
}
客户端代码
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.Charset;

/**
 * @Author: jie.wu
 * @Version: v1.0
 * @Date:2019-01-29 14:09
 */
public class Client {

    public static void main(String [] args){
        Client c=new Client();
        c.client();
    }

    public void client(){
        Socket socket=new Socket();
        OutputStream outputStream=null;
        PrintWriter printWriter=null;
        InputStream inputStream=null;
        BufferedReader bufferedReader=null;
        try {
            socket.connect(new InetSocketAddress("127.0.0.1", 10000));
            outputStream=socket.getOutputStream();
            printWriter=new PrintWriter(new OutputStreamWriter(outputStream, Charset.defaultCharset().name()),true);
            printWriter.println("你好,我是客户端");
            printWriter.println("end");
            inputStream=socket.getInputStream();
            bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
            //readLine 会造成服务器端阻塞,服务器端要么加以判断主动关闭,要么等待客户端关闭,要么新起一个线程

            //客户端可以主动结束发送信息
            //socket.shutdownOutput();

            String str;
            System.out.print("服务端回复:");
            for(;(str=bufferedReader.readLine())!=null;){
                if("end".equals(str)){
                    break;
                }
                System.out.print(str);
            }
            /*
            char[] b=new char[8192];
            StringBuffer sbf=new StringBuffer();
            for(int n=0;(n=bufferedReader.read(b,0,n))>-1;){
                sbf.append(b);
            }
            System.out.println(sbf.toString());
            */
        }catch(Exception e){
            System.out.println("报错了"+e);
        }finally {
            try{
                if(outputStream!=null){outputStream.close();}
                if(printWriter!=null){printWriter.close();}
                if(inputStream!=null){inputStream.close();}
                if(bufferedReader!=null){bufferedReader.close();}
            }catch(Exception e){
                System.out.println("真的报错了"+e);
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/bestcxx/article/details/86710025