Tcp投票通信例子

用到的二进制编码:

import java.io.*;

/* Wire Format
 *                                1  1  1  1  1  1
 *  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 * |     Magic       |Flags|       ZERO            |
 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 * |                  Candidate ID                 |
 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 * |                                               |
 * |         Vote Count (only in response)         |
 * |                                               |
 * |                                               |
 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 */
public class VoteMsgBinCoder implements VoteMsgCoder {

    // manifest constants for encoding
    public static final int MIN_WIRE_LENGTH = 4;
    public static final int MAX_WIRE_LENGTH = 16;
    public static final int MAGIC = 0x5400;
    public static final int MAGIC_MASK = 0xfc00;
    public static final int MAGIC_SHIFT = 8;
    public static final int RESPONSE_FLAG = 0x0200;
    public static final int INQUIRE_FLAG = 0x0100;

    public byte[] toWire(VoteMsg msg) throws IOException {
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        DataOutputStream out = new DataOutputStream(byteStream); // converts ints

        short magicAndFlags = MAGIC;
        if (msg.isInquiry()) {
            magicAndFlags |= INQUIRE_FLAG;
        }
        if (msg.isResponse()) {
            magicAndFlags |= RESPONSE_FLAG;
        }
        out.writeShort(magicAndFlags);
        // We know the candidate ID will fit in a short: it's > 0 && < 1000
        out.writeShort((short) msg.getCandidateID());
        if (msg.isResponse()) {
            out.writeLong(msg.getVoteCount());
        }
        out.flush();
        byte[] data = byteStream.toByteArray();
        return data;
    }

    public VoteMsg fromWire(byte[] input) throws IOException {
        // sanity checks
        if (input.length < MIN_WIRE_LENGTH) {
            throw new IOException("Runt message");
        }
        ByteArrayInputStream bs = new ByteArrayInputStream(input);
        DataInputStream in = new DataInputStream(bs);
        int magic = in.readShort();
        if ((magic & MAGIC_MASK) != MAGIC) {
            throw new IOException("Bad Magic #: " +
                    ((magic & MAGIC_MASK) >> MAGIC_SHIFT));
        }
        boolean resp = ((magic & RESPONSE_FLAG) != 0);
        boolean inq = ((magic & INQUIRE_FLAG) != 0);
        int candidateID = in.readShort();
        if (candidateID < 0 || candidateID > 1000) {
            throw new IOException("Bad candidate ID: " + candidateID);
        }
        long count = 0;
        if (resp) {
            count = in.readLong();
            if (count < 0) {
                throw new IOException("Bad vote count: " + count);
            }
        }
        // Ignore any extra bytes
        return new VoteMsg(resp, inq, candidateID, count);
    }
}

一.服务端

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class VoteServerTCP {
    public static void main(String args[]) throws Exception {
        ServerSocket servSock = new ServerSocket(9000);
        //基于二进制的编码协议消息格式
        VoteMsgCoder coder = new VoteMsgBinCoder();
        VoteService service = new VoteService();
        while (true) {
            //接受客户端请求(没有客户端请求时是阻塞的)
            Socket clntSock = servSock.accept();
            System.out.println("Handling client at " + clntSock.getRemoteSocketAddress());
            //基于长度的成帧方法
            Framer framer = new LengthFramer(clntSock.getInputStream());
            try {
                byte[] req;
                //从输入流中读取下一条信息(底层会调用in.read()方法.此方法是阻塞的,直到输入的数据是可读时.)
                while ((req = framer.nextMsg()) != null) {//读到了输入流的末端,就会跳出循环
                    System.out.println("Received message (" + req.length + " bytes)");
                    //将信息转换成VoteMsg实例(相当于反序列化)
                    VoteMsg responseMsg = service.handleRequest(coder.fromWire(req));
                    //将信息转换成byte字节(相当于序列化),并发送到客户端.
                    framer.frameMsg(coder.toWire(responseMsg), clntSock.getOutputStream());
                }
            } catch (IOException ioe) {
                System.err.println("Error handling client: " + ioe.getMessage());
            } finally {
                System.out.println("Closing connection");
                //关闭socket
                clntSock.close();
            }
        }
    }
}

还有服务端处理查询与投票请求的服务类

import java.util.HashMap;
import java.util.Map;

public class VoteService {

    // Map of candidates to number of votes
    private Map<Integer, Long> results = new HashMap<Integer, Long>();

    public VoteMsg handleRequest(VoteMsg msg) {
        if (msg.isResponse()) { // If response, just send it back
            return msg;
        }
        msg.setResponse(true); // Make message a response
        // Get candidate ID and vote count
        int candidate = msg.getCandidateID();
        Long count = results.get(candidate);
        if (count == null) {
            count = 0L; // Candidate does not exist
        }
        if (!msg.isInquiry()) {
            results.put(candidate, ++count); // If vote, increment count
        }
        msg.setVoteCount(count);
        return msg;
    }
}

二.客户端

import java.io.OutputStream;
import java.net.Socket;

public class VoteClientTCP {

    public static final int CANDIDATEID = 888;

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

        Socket sock = new Socket("127.0.0.1", 9000);
        OutputStream out = sock.getOutputStream();

        //创建一个二进制编码实例
        VoteMsgCoder coder = new VoteMsgBinCoder();
        //创建一个基于长度的成帧方法实例
        Framer framer = new LengthFramer(sock.getInputStream());

        //创建一个查询请求消息
        VoteMsg msg = new VoteMsg(false, true, CANDIDATEID, 0);
        //将消息转成字节码(相当于序列化))
        byte[] encodedMsg = coder.toWire(msg);

        System.out.println("Sending Inquiry (" + encodedMsg.length + " bytes): ");
        System.out.println(msg);
        //发送查询请求
        framer.frameMsg(encodedMsg, out);

        //改为投票请求
        msg.setInquiry(false);
        //将消息转成字节码(相当于序列化)
        encodedMsg = coder.toWire(msg);
        System.out.println("Sending Vote (" + encodedMsg.length + " bytes): ");
        //发送投票请求
        framer.frameMsg(encodedMsg, out);

        //从响应取出查询消息
        encodedMsg = framer.nextMsg();
        //转为VoteMsg实例(相当于反序列化)
        msg = coder.fromWire(encodedMsg);
        System.out.println("Received Response (" + encodedMsg.length + " bytes): ");
        System.out.println(msg);

        //从响应取出投票消息
        encodedMsg = framer.nextMsg();
        msg = coder.fromWire(encodedMsg);
        System.out.println("Received Response (" + encodedMsg.length + " bytes): ");
        System.out.println(msg);
        //关闭socket
        sock.close();
    }
}

猜你喜欢

转载自blog.csdn.net/xiejx618/article/details/51154976
今日推荐