Java Socket编程与客户/服务器应用开发(三)

来源:互联网 发布:河北工龄工资算法 编辑:程序博客网 时间:2024/06/03 15:04

流式Socket API:

数据包Socket API支持离散数据单元(即数据包)交换,流式Socket API则提供了基于UNIX操作系统的流式IO的数据传输模式。
根据定义,流式Socket API仅支持面向连接通信


流式Socket为两个特定进程提供稳定的数据交换模型。数据流从一方连续写入,从另一方读出。流的特性允许以不同速度向流中写入或读取数据,但是一个流式Socket 不能用于同时与两个及其以上的进程通信。




在Java中,有两个类提供了流式Socket API:ServerSocket和Socket。

1)ServerSocket用于接受连接,称之为连接Socket。

2)Socket用于数据交换,称之为数据Socket。


采用该API,服务器进程建立一个连接Socket,随后侦听来自其他进程的连接请求。每次只接受一个连接请求。当连接被接受后,将为该连接创建一个数据Socket。服务器进程可通过数据Socket从数据流读取数据或向其中写入数据。一旦两进程之间的通信会话结束,数据Socket被关闭,服务器可通过连接Socket自由接收下一个连接请求。


客户进程创建一个Socket,随后通过服务器的连接Socket向服务器发送连接请求。一旦请求被接受,客户Socket与服务器数据Socket连接,以便客户可继续从数据流读取数据或向数据流写入数据。当两进程之间的通信会话结束后,数据Socket关闭。


ServerSocket 的 accept()方法是阻塞操作,如果没有正在等待的请求,服务器进程被挂起,直到连接请求到达。

Socket 的输入流中读取数据时,即InputStream的read()方法是阻塞操作,如果请求的所有数据没有全部到达该输入流中,客户进程将被阻塞,直到有足够数量的数据被写入数据流。


public class SocketServerConnectionAcceptor {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        try {            //服务器监听端口            int portNo=9527;            ServerSocket connectionSocket = new ServerSocket(portNo);            System.out.println("now ready accept a connection~");            //阻塞监听连接            Socket dataSocket=connectionSocket.accept();            //可以从socket里获得发送方的地址和端口,以及接收方的地址和端口            System.out.println(dataSocket.getInetAddress()+"  "+dataSocket.getPort()+"   "                    +dataSocket.getRemoteSocketAddress()+"   "+dataSocket.getLocalPort()+"   "                    +dataSocket.getLocalAddress());            System.out.println("connection accepted:");            OutputStream outputStream=dataSocket.getOutputStream();            PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(outputStream));            for(int i=0;i<5;i++) {                String msg=scanner.nextLine();                printWriter.println(msg);                printWriter.flush();            }            System.out.println("message sent!!");            //先关掉数据Socket            dataSocket.close();            System.out.println("data socket closed!");            //再关掉连接Socket            connectionSocket.close();            System.out.println("connection socket closed!");        } catch (Exception e) {            e.printStackTrace();        }    }}



public class SocketConnectionRequestor {    public static void main(String []args) {        try {            //服务器地址和端口号            InetAddress acceptorHost = InetAddress.getByName("127.0.0.1");            int acceptorPort=9527;            SocketAddress socketAddress = new InetSocketAddress(acceptorHost, acceptorPort);            //数据Socket            Socket mySocket = new Socket();            //最大等待连接时长            int timeoutPeriod=5000;            mySocket.connect(socketAddress,timeoutPeriod);            System.out.println("Connection request granted!!");            //可以从socket里获得发送方的地址和端口,以及接收方的地址和端口            System.out.println(mySocket.getInetAddress()+"  "+mySocket.getPort()+"   "                    +mySocket.getRemoteSocketAddress()+"   "+mySocket.getLocalPort()+"   "                    +mySocket.getLocalAddress());            InputStream inputStream=mySocket.getInputStream();            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));            System.out.println("waiting to read!!");            for(int i=0;i<5;i++) {                String msg=bufferedReader.readLine();                System.out.println("Message received:");                System.out.println("\t"+msg);            }            mySocket.close();            System.out.println("data socket closed!!");        } catch (Exception e) {            e.printStackTrace();        }    }}



以上是服务器写数据,客户端读数据;其实完全可以双方都写、读。

当使用PrintWriter向 Socket流写入数据时,必须使用flush()方法调用来真正地填充与刷新该流,从而确保所有数据都可以在像Socket突然关闭等意外情形发生之前,尽可能快地从数据缓冲区中真正地写入数据流。


为允许将程序中的应用逻辑和服务逻辑分离,采用了隐藏数据Socket细节的子类。

public class MyStreamSocket{   private Socket  socket;   private BufferedReader input;   private PrintWriter output;   MyStreamSocket(String acceptorHost, int acceptorPort ) throws SocketException, IOException{      socket = new Socket(acceptorHost, acceptorPort );      setStreams();   }   MyStreamSocket(Socket socket)  throws IOException {      this.socket = socket;      setStreams();   }   private void setStreams( ) throws IOException{      // 从输入流中获取inputStream      InputStream inStream = socket.getInputStream();      input = new BufferedReader(new InputStreamReader(inStream));      OutputStream outStream = socket.getOutputStream();      // 创建一个PrintWriter来操作字符流      output = new PrintWriter(new OutputStreamWriter(outStream));   }   public void sendMessage(String message) throws IOException {      output.println(message);         //flush操作为了避免意外关闭socket而导致数据丢失      output.flush();                  } // end sendMessage   public String receiveMessage( ) throws IOException {      // 从输入流读取一行      return input.readLine( );   } //end receiveMessage   public void SocketClose() throws IOException{      socket.close();   }} //end class

使用以上封装好的Socket操作:

public class ServerSocketConnectionAcceptor {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        try {            int portNo=9527;            ServerSocket serverSocket = new ServerSocket(portNo);            System.out.println("now ready accept a connection~");            MyStreamSocket dataSocket = new MyStreamSocket(serverSocket.accept());            System.out.println("connection accepted:");            for(int i=0;i<5;i++) {                dataSocket.sendMessage(scanner.nextLine());            }            dataSocket.SocketClose();            System.out.println("data socket closed!");            serverSocket.close();            System.out.println("connection socket closed!");        } catch (Exception e) {            e.printStackTrace();        }    }}

 
public class SocketConnectionRequestor {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        try {            int serverPortNo=9527;            String serverHost = "127.0.0.1";            MyStreamSocket dataSocket = new MyStreamSocket(serverHost,serverPortNo);            System.out.println("connection request granted:");            for(int i=0;i<5;i++) {                System.out.println(dataSocket.receiveMessage());            }            dataSocket.SocketClose();            System.out.println("data socket closed!");        } catch (Exception e) {            e.printStackTrace();        }    }}



以上是服务器为单线程,若加入多线程:

public class MyStreamSocket implements Runnable{   private Socket  socket;   private BufferedReader input;   private PrintWriter output;   MyStreamSocket(String acceptorHost, int acceptorPort ) throws SocketException, IOException{      socket = new Socket(acceptorHost, acceptorPort );      setStreams();   }   MyStreamSocket(Socket socket)  throws IOException {      this.socket = socket;      setStreams();   }   ......   @Override   public void run() {      Scanner scanner = new Scanner(System.in);      try {         System.out.println("connection accepted:");         for(int i=0;i<5;i++) {            sendMessage(scanner.nextLine());         }         SocketClose();         System.out.println("data socket closed!");      } catch (Exception e) {         e.printStackTrace();      }   }} //end class



public class ServerSocketThreadConnectionAcceptor {    public static void main(String[] args) {        try {            int portNo=9527;            ServerSocket serverSocket = new ServerSocket(portNo);            System.out.println("now ready accept a connection~");            while (true) {                Socket socket=serverSocket.accept();                new Thread(new MyStreamSocket(socket)).start();            }//            serverSocket.close();//            System.out.println("connection socket closed!");        } catch (Exception e) {            e.printStackTrace();        }    }}



1 0
原创粉丝点击