You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python与Java Socket传输yfinance股票数据中断及数据限制问题求助

问题:Socket传输股票数据时仅传输部分内容后挂起

我正在开发一款程序,用于整理并压缩多只股票的yfinance数据,最终存入.txt文件。程序通过Socket实现Python服务器向Java客户端传输数据,但运行时仅能传输部分数据,随后突然停止导致程序挂起。想问是否存在数据限制阻碍完整数据传输?


Python服务器代码

import socket
import yfinance as yf
import pandas as pd
import datetime as dt

pd.options.display.max_rows = 2000000

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(("127.0.0.1", 65432))
    s.listen()
    conn, addr = s.accept()
    with conn:
        print(f"Connected by {addr}")
        while True:
            data = conn.recv(1024)
            if not data:
                print('nodata')
                break
            stringdata = data.decode('utf-8')
            print(stringdata)
            if stringdata == "end":
                break
            start1 = stringdata[0:10]
            start = dt.datetime(int(start1[0:4]), int(start1[5:7]), int(start1[8:10]))
            end1 = stringdata[10:20]
            end = dt.datetime(int(end1[0:4]), int(end1[5:7]), int(end1[8:10]))
            tticker = yf.Ticker(stringdata[20:])
            print(tticker.history(start=start, end=end, interval="5m"))
            stringdata2 = str(data2)
            print(stringdata2)
            conn.sendall(bytes(stringdata2, 'utf-8'))
        s.close()

Java客户端代码

import java.net.*;
import java.text.NumberFormat;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;  
import java.util.ArrayList;
import java.io.*;
import java.util.Scanner;

public class main{

    public static ArrayList<String> Tickers = new ArrayList<String>();
    public static File stockTracker = new File("StockTracking.txt");
    
    public static void main(String[] args) throws IOException, ParseException, InterruptedException{
        int x = 65;
        char y;
        String z;
        String x1;
        while(x <= 90) {
            y = (char)x;
            z = String.valueOf(y);
            x1 = "https://eoddata.com/stocklist/NYSE/" + z + ".htm";
            URL tickers = new URL(x1);
            URLConnection tCon = tickers.openConnection();
            InputStreamReader tStream = new InputStreamReader(tCon.getInputStream());
            BufferedReader tBuff = new BufferedReader(tStream);

            String oline = tBuff.readLine();
            while(oline != null) {
                if(oline.contains("NYSE,")){
                    String gx = oline.substring(oline.indexOf("/NYSE/") + 6, oline.indexOf(".htm"));
                    if(!(gx.equals("BRK.A")) && !(gx.equals("EVN"))) {
                        try {
                            if(!(Integer.parseInt(oline.substring(oline.indexOf("<td align=right>") + 16, oline.indexOf("<td align=right>") + 17)) < 5 
                                && oline.substring(oline.indexOf("<td align=right>") + 17, oline.indexOf("<td align=right>") + 18).equals(".")) 
                                && NumberFormat.getNumberInstance(java.util.Locale.US)
                                .parse(oline.substring(oline.indexOf("<td align=right>") + 94, oline.indexOf("</td><td align=\"right\">"))).intValue() > 1000000) {
                                Tickers.add(gx);
                                System.out.println(gx);
                            }
                        }catch(ParseException e) {
                            Tickers.add(gx);
                        }
                    }
                }
                oline = tBuff.readLine();
            }
            
            y = (char)x;
            z = String.valueOf(y);
            x1 = "https://eoddata.com/stocklist/NASDAQ/" + z + ".htm";
            URL ntickers = new URL(x1);
            URLConnection nCon = ntickers.openConnection();
            InputStreamReader nStream = new InputStreamReader(nCon.getInputStream());
            BufferedReader nBuff = new BufferedReader(nStream);

            String nline = nBuff.readLine();
            while(nline != null) {
                if(nline.contains("NASDAQ,")){
                    String gx = nline.substring(nline.indexOf("/NASDAQ/") + 8, nline.indexOf(".htm"));
                    try {
                        if(!(Integer.parseInt(nline.substring(nline.indexOf("<td align=right>") + 16, nline.indexOf("<td align=right>") + 17)) < 5 
                            && nline.substring(nline.indexOf("<td align=right>") + 17, nline.indexOf("<td align=right>") + 18).equals(".")) 
                            && NumberFormat.getNumberInstance(java.util.Locale.US)
                            .parse(nline.substring(nline.indexOf("<td align=right>") + 94, nline.indexOf("</td><td align=\"right\">"))).intValue() > 1000000) {
                            Tickers.add(gx);
                            System.out.println(gx);
                        }
                    }catch(ParseException e) {
                        Tickers.add(gx);
                    }
                }
                nline = nBuff.readLine();
            }
            x++;
        }
        for(String tick:Tickers) {
            System.out.println(tick);
        }
        
        Scanner console = new Scanner(System.in);
        
        Socket transmission = new Socket("localhost", 65432);
        System.out.println("Socket Created");
        
        Reader reader = new InputStreamReader(transmission.getInputStream());
        BufferedReader in = new BufferedReader(reader);
        
        Writer writer = new OutputStreamWriter(transmission.getOutputStream());
        BufferedWriter out = new BufferedWriter(writer);
        
        FileWriter dWriter = new FileWriter("StockTracking.txt");
        initData(in, out);
        out.write("end");
        transmission.close();
        System.out.println("Socket Closed");
    }
    
    public static boolean initData(BufferedReader in, BufferedWriter out) throws IOException, InterruptedException {
        LocalDate edate = LocalDate.now().minusDays(1);
        LocalDate sdate = LocalDate.now().minusDays(40);
        String ssdate = sdate.format(DateTimeFormatter.ISO_LOCAL_DATE);
        String sedate = edate.format(DateTimeFormatter.ISO_LOCAL_DATE);
        
        PrintWriter pw =  new PrintWriter(new FileWriter(stockTracker));
        for(String ticker:Tickers) {
            System.out.println(ticker);
            out.write(ssdate + sedate + ticker);
            out.flush();
            Thread.sleep(10);
            pw.println(ticker);
            String x;
            while(true) {
                x = in.readLine();
                System.out.println(x);
                if(x.length() > 25 && x.substring(0, 1).equals("2")) {
                    pw.println(x.substring(5, 7) + x.substring(8, 10) + x.substring(11, 13) + x.substring(14, 16) + x.substring(27, x.indexOf(".") + 2));
                    if(x.substring(5, 7).equals("07")) {
                        if(x.substring(8, 10).equals("21")) {
                            if(x.substring(11, 13).equals("15")) {
                                if(x.substring(14, 16).equals("55")) {
                                    break;
                                }
                            }  
                        }
                    }
                }
            }
            pw.flush();
        }
        pw.close();
        return false;
    }
}

问题根源与解决方案

1. 核心语法错误(Python端)

  • print(tticker.history(...))缺少闭合括号,会直接导致程序崩溃中断。
  • stringdata2 = str(data2)中的data2未定义,正确写法应为先获取历史数据再转换:
    data2 = tticker.history(start=start, end=end, interval="5m")
    stringdata2 = str(data2)
    

2. Socket流式传输的边界问题

Socket是无消息边界的流式协议,直接传输字符串会导致两端无法判断数据是否传输完成,进而引发挂起:

  • Python端改进:在数据末尾添加明确的结束标记,告知客户端传输完成:
    data2 = tticker.history(start=start, end=end, interval="5m")
    stringdata2 = str(data2) + "\nDATA_END\n"
    conn.sendall(stringdata2.encode('utf-8'))
    
  • Java端改进:替换原有的日期判断逻辑,改为读取直到遇到结束标记:
    StringBuilder sb = new StringBuilder();
    String line;
    while ((line = in.readLine()) != null) {
        if (line.equals("DATA_END")) {
            break;
        }
        sb.append(line).append("\n");
    }
    String fullStockData = sb.toString();
    // 处理数据写入文件
    

3. 数据接收截断问题

Python端conn.recv(1024)每次仅接收1024字节,若客户端发送的请求(日期+股票代码)超过该长度,会导致数据截断,解析时出错。需循环接收完整请求:

def recv_full_message(conn):
    buffer = b''
    while True:
        chunk = conn.recv(1024)
        if not chunk:
            return None
        buffer += chunk
        if b'\n' in chunk:  # 客户端发送请求时需添加换行标记
            break
    return buffer.decode('utf-8').strip()

替换原代码中的data = conn.recv(1024)为stringdata = recv_full_message(conn),同时Java端发送请求时添加换行:

out.write(ssdate + sedate + ticker + "\n");
out.flush();

4. 资源释放问题

Python端使用with语句已自动处理Socket关闭,无需额外调用s.close();Java端需确保initData执行完毕后,关闭输入输出流,避免资源泄漏。


内容的提问来源于stack exchange,提问作者IneptDwarf33872

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 09:14:56