Java Socket通讯

一、Java 为Socket通讯提供哪些类:

1)、 ServerSocket类
    
创建一个ServerSocket类,同时在运行该语句的计算机的指定端口处建立一个监听服务,如:
    ServerSocket MyListener=new ServerSocket(600);
    这里指定提供监听服务的端口是600,一台计算机可以同时提供多个服务,这些不同的服务之间通过端口号来区别,不同的端口号上提供不同的服务。为了随时监听可能的Client请求,执行如下的语句:
    Socket LinkSocket=MyListener.accept();
    该语句调用了ServerSocket对象的accept()方法,这个方法的执行将使Server端的程序处于等待状态,程序将一直阻塞直到捕捉到一个来自Client端的请求,并返回一个用于与该Client通信的Socket对象Link-Socket。此后Server程序只要向这个Socket对象读写数据,就可以实现向远端的Client读写数据。结束监听时,关闭ServerSocket对象:
    Mylistener.close();
2)、 Socket类
    当Client程序需要从Server端获取信息及其他服务时,应创建一个Socket对象:
    Socket MySocket=new Socket(“ServerComputerName”,600);
    Socket类的构造函数有两个参数,第一个参数是欲连接到的Server计算机的主机地址,第二个参数是该Server机上提供服务的端口号。
    Socket对象建立成功之后,就可以在Client和Server之间建立一个连接,并通过这个连接在两个端点之间传递数据。利用Socket类的方法getOutputStream()和getInputStream()分别获得向Socket读写数据的输入/输出流,最后将从Server端读取的数据重新返还到Server端。
    当Server和Client端的通信结束时,可以调用Socket类的close()方法关闭Socket,拆除连接。

ServerSocket 一般仅用于设置端口号和监听,真正进行通信的是服务器端的Socket与客户端的Socket,在ServerSocket 进行accept之后,就将主动权转让了。

二、程序设计:

1)、 服务器端程序设计
    在服务器端,利用ServerSocket类的构造函数ServerSocket(int port)创建一个ServerSocket类的对象,port参数传递端口,这个端口就是服务器监听连接请求的端口,如果在这时出现错误将抛出IOException异常对象,否则将创建ServerSocket对象并开始准备接收连接请求。
    服务程序从调用ServerSocket的accept()方法开始,直到连接建立。在建立连接后,accept()返回一个最近创建的Socket对象,该Socket对象绑定了客户程序的IP地址或端口号。
2)、客户端程序设计
    当客户程序需要与服务器程序通信时,需在客户机创建一个Socket对象。Socket类有构造函数Socket(InetAddress addr,int port)和Socket(String host,intport),两个构造函数都创建了一个基于Socket的连接服务器端流套接字的流套接字。对于第一个InetAd-dress子类对象通过addr参数获得服务器主机的IP地址,对于第二个函数host参数包被分配到InetAddress对象中,如果没有IP地址与host参数相一致,那么将抛出UnknownHostException异常对象。两个函数都通过参数port获得服务器的端口号。假设已经建立连接了,网络API将在客户端基于Socket的流套接字中捆绑客户程序的IP地址和任意一个端口号,否则两个函数都会抛出一个IOException对象。
    如果创建了一个Socket对象,那么它可通过get-InputStream()方法从服务程序获得输入流读传送来的信息,也可通过调用getOutputStream()方法获得输出流来发送消息。在读写活动完成之后,客户程序调用close()方法关闭流和流套接字。

三、程序示例:

*普通IO方式:

1.服务端程序

View Code
/**

 * @msg 服务器端程序

 */

import java.net.*;

import java.io.*;



public class echoServer

{

    private int port = 7890;

    private ServerSocket serverSocket;



    public echoServer() throws IOException

    {

        serverSocket = new ServerSocket(port);//启动一个socket服务器

        System.out.println("服务器已启动!");

    }



    public String echo(String msg)

    {

        return "echo:"+msg;

    }



    private PrintWriter getWriter(Socket socket) throws IOException

    {

        OutputStream socketOut = socket.getOutputStream();

        return new PrintWriter( socketOut , true);

    }



    private BufferedReader getReader(Socket socket) throws IOException

    {

        InputStream socketIn = socket.getInputStream();

        return new BufferedReader(new InputStreamReader(socketIn));

    }



    public void server()

    {

        while(true)

        {

            Socket socket=null;

            try

            {

                socket = serverSocket.accept();//阻塞方法,等待客户端连接

                System.out.println("New connection accepted"+

                    socket.getInetAddress()+":"+socket.getPort());

                BufferedReader br = getReader(socket);//获取读取客户端信息的Reader

                PrintWriter pw = getWriter(socket);//获取往客户端传送信息的Writer



                String msg = null;

                while((msg = br.readLine())!=null)

                {

                    System.out.println(msg);//打印客户端传来的信息

                    pw.println(echo(msg));//把信息再回传给客户端

                    if(msg.equals("bye"))

                    break;

                }

            }

            catch (IOException e)

            {

                e.printStackTrace();

            }

            finally

            {

                try

                {

                    if(socket!=null)

                        socket.close();

                }

                catch (IOException e)

                {

                    e.printStackTrace();

                }

            }

        }

    }



    public static void main(String[] args) throws IOException

    {

        new echoServer().server();

    }

}

 2.客户端程序

View Code
import java.io.*;

import java.net.*;



public class Client {

    Socket socket;

    BufferedReader in;

    PrintWriter out;



    public Client() {

        try {

            System.out.println("Try to Connect to 127.0.0.1:7890");

            socket = new Socket("127.0.0.1", 7890);//连接服务器

            System.out.println("The Server Connected!");

            System.out.println("Please enter some Character:");

            BufferedReader line = new BufferedReader(new InputStreamReader(

                    System.in));//客户端从键盘获取要发送的信息

            out = new PrintWriter(socket.getOutputStream(), true);//获取往服务端传信息的out

            out.println(line.readLine());//向服务端传送信息

            in = new BufferedReader(new InputStreamReader(socket

                    .getInputStream()));//获取读取服务单信息的in

            System.out.println(in.readLine());//服务端回应的信息

            out.close();

            in.close();

            socket.close();

        } catch (IOException e) {

            //out.println("Wrong");

        }

    }



    public static void main(String[] args) {

        new Client();

    }

}

*NIO方式:

 1.服务端程序

View Code
import java.io.IOException;

import java.net.InetSocketAddress;

import java.net.ServerSocket;

import java.nio.ByteBuffer;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.ServerSocketChannel;

import java.nio.channels.SocketChannel;

import java.util.Iterator;

import java.util.Set;



public class NIOServer {

    

    /*标识数字*/

    private  int flag = 0;

    /*缓冲区大小*/

    private  int BLOCK = 4096;

    /*接受数据缓冲区*/

    private  ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);

    /*发送数据缓冲区*/

    private  ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);

    private  Selector selector;



    public NIOServer(int port) throws IOException {

        // 打开服务器套接字通道

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 服务器配置为非阻塞

        serverSocketChannel.configureBlocking(false);

        // 检索与此通道关联的服务器套接字

        ServerSocket serverSocket = serverSocketChannel.socket();

        // 进行服务的绑定

        serverSocket.bind(new InetSocketAddress(port));

        // 通过open()方法找到Selector

        selector = Selector.open();

        // 注册到selector,等待连接

        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        System.out.println("Server Start----8888:");

    }





    // 监听

    private void listen() throws IOException {

        while (true) {

            // 选择一组键,并且相应的通道已经打开

            selector.select();

            // 返回此选择器的已选择键集。

            Set<SelectionKey> selectionKeys = selector.selectedKeys();

            Iterator<SelectionKey> iterator = selectionKeys.iterator();

            while (iterator.hasNext()) {        

                SelectionKey selectionKey = iterator.next();

                iterator.remove();

                handleKey(selectionKey);

            }

        }

    }



    // 处理请求

    private void handleKey(SelectionKey selectionKey) throws IOException {

        // 接受请求

        ServerSocketChannel server = null;

        SocketChannel client = null;

        String receiveText;

        String sendText;

        int count=0;

        // 测试此键的通道是否已准备好接受新的套接字连接。

        if (selectionKey.isAcceptable()) {

            // 返回为之创建此键的通道。

            server = (ServerSocketChannel) selectionKey.channel();

            // 接受到此通道套接字的连接。

            // 此方法返回的套接字通道(如果有)将处于阻塞模式。

            client = server.accept();

            // 配置为非阻塞

            client.configureBlocking(false);

            // 注册到selector,等待连接

            client.register(selector, SelectionKey.OP_READ);

        } else if (selectionKey.isReadable()) {

            // 返回为之创建此键的通道。

            client = (SocketChannel) selectionKey.channel();

            //将缓冲区清空以备下次读取

            receivebuffer.clear();

            //读取服务器发送来的数据到缓冲区中

            count = client.read(receivebuffer);    

            if (count > 0) {

                receiveText = new String( receivebuffer.array(),0,count);

                System.out.println("服务器端接受客户端数据--:"+receiveText);

                client.register(selector, SelectionKey.OP_WRITE);

            }

        } else if (selectionKey.isWritable()) {

            //将缓冲区清空以备下次写入

            sendbuffer.clear();

            // 返回为之创建此键的通道。

            client = (SocketChannel) selectionKey.channel();

            sendText="message from server--" + flag++;

            //向缓冲区中输入数据

            sendbuffer.put(sendText.getBytes());

             //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位

            sendbuffer.flip();

            //输出到通道

            client.write(sendbuffer);

            System.out.println("服务器端向客户端发送数据--:"+sendText);

            client.register(selector, SelectionKey.OP_READ);

        }

    }



    /**

     * @param args

     * @throws IOException

     */

    public static void main(String[] args) throws IOException {

        // TODO Auto-generated method stub

        int port = 8888;

        NIOServer server = new NIOServer(port);

        server.listen();

    }

}

2.客户端程序

View Code
import java.io.IOException;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.SocketChannel;

import java.util.Iterator;

import java.util.Set;



public class NIOClient {



    /*标识数字*/

    private static int flag = 0;

    /*缓冲区大小*/

    private static int BLOCK = 4096;

    /*接受数据缓冲区*/

    private static ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);

    /*发送数据缓冲区*/

    private static ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);

    /*服务器端地址*/

    private final static InetSocketAddress SERVER_ADDRESS = new InetSocketAddress(

            "localhost", 8888);



    public static void main(String[] args) throws IOException {

        // 打开socket通道

        SocketChannel socketChannel = SocketChannel.open();

        // 设置为非阻塞方式

        socketChannel.configureBlocking(false);

        // 打开选择器

        Selector selector = Selector.open();

        // 注册连接服务端socket动作

        socketChannel.register(selector, SelectionKey.OP_CONNECT);

        // 连接

        socketChannel.connect(SERVER_ADDRESS);

        // 分配缓冲区大小内存

        

        Set<SelectionKey> selectionKeys;

        Iterator<SelectionKey> iterator;

        SelectionKey selectionKey;

        SocketChannel client;

        String receiveText;

        String sendText;

        int count=0;



        while (true) {

            //选择一组键,其相应的通道已为 I/O 操作准备就绪。

            //此方法执行处于阻塞模式的选择操作。

            selector.select();

            //返回此选择器的已选择键集。

            selectionKeys = selector.selectedKeys();

            //System.out.println(selectionKeys.size());

            iterator = selectionKeys.iterator();

            while (iterator.hasNext()) {

                selectionKey = iterator.next();

                if (selectionKey.isConnectable()) {

                    System.out.println("client connect");

                    client = (SocketChannel) selectionKey.channel();

                    // 判断此通道上是否正在进行连接操作。

                    // 完成套接字通道的连接过程。

                    if (client.isConnectionPending()) {

                        client.finishConnect();

                        System.out.println("完成连接!");

                        sendbuffer.clear();

                        sendbuffer.put("Hello,Server".getBytes());

                        sendbuffer.flip();

                        client.write(sendbuffer);

                    }

                    client.register(selector, SelectionKey.OP_READ);

                } else if (selectionKey.isReadable()) {

                    client = (SocketChannel) selectionKey.channel();

                    //将缓冲区清空以备下次读取

                    receivebuffer.clear();

                    //读取服务器发送来的数据到缓冲区中

                    count=client.read(receivebuffer);

                    if(count>0){

                        receiveText = new String( receivebuffer.array(),0,count);

                        System.out.println("客户端接受服务器端数据--:"+receiveText);

                        client.register(selector, SelectionKey.OP_WRITE);

                    }



                } else if (selectionKey.isWritable()) {

                    sendbuffer.clear();

                    client = (SocketChannel) selectionKey.channel();

                    sendText = "message from client--" + (flag++);

                    sendbuffer.put(sendText.getBytes());

                     //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位

                    sendbuffer.flip();

                    client.write(sendbuffer);

                    System.out.println("客户端向服务器端发送数据--:"+sendText);

                    client.register(selector, SelectionKey.OP_READ);

                }

            }

            selectionKeys.clear();

        }

    }

}

 

 

 

 

 

 

 

 

你可能感兴趣的:(java socket)