Flink证券项目(六) 客户端程序

105 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

客户端程序

客户端负责接收服务端广播的实时行情数据,并对数据预处理加工,发送到消息队列Kafka中。 1.获取服务端数据 在cn.itcast.szse包下创建客户端接收数据对象:SocketClient 开发步骤: 1.创建main方法 2.建立socket连接,获取流数据 3.读文件缓存成交量和成交金额 4.解析行数据,数据转换 发送kafka

代码略

2.读取文件缓存成交数据 解析文件获取成交量和成交金额数据,并封装到Map<String, Map<String, Long>> map中。

开发步骤: 1.读取本地文件(深市) 2.解析行数据获取成交量和成交金额 3.封装数据到map 4.关流

注意:需要加载外部数据源基础文件,拷贝”4.资料\需求文档\数据源接口文档\数据源文件“中的szse-index.txt和szse-stock.txt到自定义本地磁盘文件目录下:E:\export\servers\tmp\socket

/**
 * 深市行情实时采集数据
 */
public class SocketClient {

    private static Map<String, Map<String, Long>> map = new HashMap<>();

    //1.创建main方法
public static void main(String[] args) throws IOException {
        
        //2.socket连接,获取流数据
        Socket socket = new Socket(host, port);
        InputStream inputStream = socket.getInputStream();
        DataInputStream dataInputStream = new DataInputStream(inputStream);
	
	   //3.读文件缓存成交量和成交金额
        parseFile();
    }

    public static void parseFile() {
        try {
		 //1.读取本地文件(个股、指数)
            //个股
            BufferedReader brSzseStock = new BufferedReader(new InputStreamReader(new FileInputStream(new File("E:\\export\\servers\\tmp\\socket\\szse-stock.txt")), "UTF-8"));
            
		 //2.解析行数据获取成交量和成交金额
    	    String lineTxtStock = null;
    	    while ((lineTxtStock = brSzseStock.readLine()) != null) {
    	        String[] arr = lineTxtStock.split("\\|");
    	        String code = arr[1].trim();
    	        long tradeVol = new Long(arr[3].trim()).longValue();
    	        long tradeAmt = Double.valueOf(arr[4].trim()).longValue();
			//3.封装数据到map
    	        Map<String, Long> volAmtMap = new HashMap<>();
    	        volAmtMap.put("tradeVol", tradeVol);
    	        volAmtMap.put("tradeAmt", tradeAmt);
    	        map.put(code, volAmtMap);
    	    }
			
		 //4.关流
    	    brSzseStock.close();
		
    	    //指数
    	    BufferedReader brSzseIndex = new BufferedReader(new InputStreamReader(new FileInputStream(new File("E:\\export\\servers\\tmp\\socket\\szse-index.txt")), "UTF-8"));
    	    //2.解析行数据获取成交量和成交金额
    	    String lineTxtIndex = null;
    	    while ((lineTxtIndex = brSzseIndex.readLine()) != null) {
    	        String[] arr = lineTxtIndex.split("\\|");
    	        Map<String, Long> volAmtMap = new HashMap<>();
    	        String code = arr[1].trim();
    	        Long tradeVol = new Long(arr[3].trim()).longValue();
    	        long tradeAmt = Double.valueOf(arr[4].trim()).longValue();
			//3.封装数据到map
    	        volAmtMap.put("tradeVol", tradeVol);
    	        volAmtMap.put("tradeAmt", tradeAmt);
    	        map.put(code, volAmtMap);
    	    }
		//4.关流
    	    brSzseIndex.close();
    	} catch (Exception e) {
    	    System.err.println("errors :" + e);
    	}
    }
}

3.解析数据 第一步:在main方法中添加解析数据代码

//3.解析行数据,数据转换

while (true) {
    String readUTF = dataInputStream.readUTF();
    //数据转换成avro
    StockAvro stockAvro = transform(readUTF);
    System.out.println(stockAvro);
}

第二步:新建数据转换方法transform

开发步骤: 1.拷贝成交量和成交价数组 2.获取随机浮动成交量和价格 3.字符串切割、计算最新价 4.获取缓存的成交量/金额 计算总成交量/金额 6.缓存总成交量/金额 7.获取最高价和最低价(和最新价比较) 8.封装结果数据

//随机浮动成交价格系数 private static Double[] price = new Double[]{0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, -0.1, -0.11, -0.12, -0.13, -0.14, -0.15, -0.16, -0.17, -0.18, -0.19, -0.2};

//随机浮动成交量 private static int[] volumn = new int[]{50, 80, 110, 140, 170, 200, 230, 260, 290, 320, 350, 380, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300};

 /**

 * 字符串转换成avro对象
   */
   private static SzsekAvro transform(String str) {

   //1.字符串切割
   String[] arr = str.split("\\|");
   //2.获取随机浮动成交量和价格
   Random random = new Random();
   int priceIndex = random.nextInt(price.length);
   Double priceRandom = price[priceIndex];
   int volumnIndex = random.nextInt(volumn.length);
   int volumnRandom = volumn[volumnIndex];

   //3.计算最新价
   BigDecimal tradePriceBase = new BigDecimal(arr[9].trim());
   BigDecimal tradePrice = tradePriceBase.multiply(new BigDecimal(1 + priceRandom))
           .setScale(2, BigDecimal.ROUND_HALF_UP);

   //4.获取缓存的成交量/金额
   Map<String, Long> volAmtMap = map.get(arr[1].trim());
   Long tradeVol = 0l;
   Long tradeAmt = 0l;
   tradeVol = volAmtMap.get("tradeVol");
   tradeAmt = volAmtMap.get("tradeAmt");

   //计算总成交量/金额
   //总成交量
   Long tradeVolNew = 0l;
   if (tradeVol != 0) {
       tradeVolNew = tradeVol + volumnRandom;
   }
   //总成交金额
   BigDecimal amt = tradePrice.multiply(new BigDecimal(volumnRandom)).setScale(2, RoundingMode.HALF_UP);
   Long tradeAmtNew = tradeAmt + amt.longValue();

   //缓存最新成交量和成交金额
   volAmtMap.put("tradeVol", tradeVolNew);
   volAmtMap.put("tradeAmt", tradeAmtNew);
   map.put(arr[1].trim(), volAmtMap);

   //6.获取最高价和最低价
   //计算最高价
   BigDecimal highPrice = new BigDecimal(arr[7].trim());
   //最高价和最新价比较
   if (tradePrice.compareTo(highPrice) == 1) {
       highPrice = tradePrice;
   }

   //计算最低价
   BigDecimal lowPrice = new BigDecimal(arr[8].trim());
   //最低价和最新价比较
   if (tradePrice.compareTo(lowPrice) == -1) {
       lowPrice = tradePrice;
   }

   //7.封装结果数据
   SzsekAvro szsekAvro = new SzsekAvro();
   szsekAvro.setMdStreamID(arr[0].trim());
   szsekAvro.setSecurityID(arr[1].trim());
   szsekAvro.setSymbol(arr[2].trim());
   szsekAvro.setTotalValueTraded(tradeAmtNew);
   szsekAvro.setTradeVolume(tradeVolNew);
   szsekAvro.setPreClosePx(Double.valueOf(arr[5].trim()));
   szsekAvro.setOpenPrice(Double.valueOf(arr[6].trim()));
   szsekAvro.setHighPrice(highPrice.doubleValue());
   szsekAvro.setLowPrice(lowPrice.doubleValue());
   szsekAvro.setTradePrice(tradePrice.doubleValue());
   szsekAvro.setClosePx(tradePrice.doubleValue());
   szsekAvro.setTradingPhaseCode(arr[11].trim());
   szsekAvro.setTimestamp(new Date().getTime());
   szsekAvro.setMarket("szse");
   return szsekAvro;
   }

4.发送Kafka 数据发送Kafka需要提前创建Kafka生产者对象,并提前创建好topic。 4.1.Kafka生产者对象 开发步骤: 1.创建类,泛型参数继承avro基类 2.设置生产者参数 3.自定avro序列化 4.添加发送数据方法

生产者参数: bootstrap.servers :broker地址 acks :0,1和-1 retries:重试次数 batch.size:批量发送大小默认16384 (16kB) linger.ms: 定时发送1ms buffer.memory: 缓存大小33554432 key.serializer:key序列化 value.serializer: value序列化

代码略

4.2.自定义Avro序列化 在cn.itcast.avro目录创建序列化对象:AvroSerializer 开发步骤: 1.泛型参数继承avro基类,实现序列化接口 2.重写序列化方法 3.新建字节数组输出流对象 4.获取二进制对象BinaryEncoder 输出数据

代码略

数据发送 在while循环中发送转换之后的数据

while (true) {
    String readUTF = dataInputStream.readUTF();
    //数据转换成avro
    StockAvro stockAvro = transform(readUTF);
    //7.发送kafka
    kafkaPro.sendData("szse", stockAvro);
}

6.打包部署 1.导入依赖

代码略

2.打包

启动命令 服务端:nohub -java -jar szse-server.jar & 客户端:nohub -java -jar szse-client.jar & 注意: 1.需要新建topic:szse bin/kafka-topics.sh --create --partitions 1 --replication-factor 1 --zookeeper node01:2181 --topic szse 2.如果部署在服务器上需要在代码中修改文件解析的服务器路径 BufferedReader brSzseStock = new BufferedReader(new InputStreamReader(new FileInputStream(new File("E:\export\servers\tmp\socket\szse-stock.txt")), "UTF-8"));