Windows下Python通过stdin向C++子进程传递字节失败
解决Windows下Python子进程管道向C++程序传递大字节数据的EOF问题
Ubuntu Linux上运行正常,但Windows环境下,Python通过Popen向C子进程的stdin管道写入1000字节时,C端的fread会提前触发EOF,后续重复保存最后读取的字节。小数据(10-200字节)正常,300-500字节偶尔失败,1000字节必然失败,读取成功的字节数不固定。
以下是几种有效的解决方法:
方法1:通过communicate直接传递输入(推荐)
原代码中手动调用proc.stdin.write后再调用communicate会导致管道状态异常,改用communicate(input=inp)统一处理输入写入和管道关闭,确保C++端能收到完整的EOF信号。
修改Python侧的run_cpp函数:
def run_cpp(vars): command = os.path.join('.', 'program') inp = bytes(vars) proc = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE, text=False) res, err = proc.communicate(input=inp) # 直接通过communicate传递输入 print('python wrote:', len(inp),'bytes\n') print('vars read by c++:') print('\n'+'stderr:', err, '\n') print('stdout:', res, '\n') return
方法2:将C++端stdin设置为无缓冲模式
Windows下stdio默认的缓冲机制可能导致管道数据未及时刷新,引发EOF误判。在C++程序中禁用stdin缓冲:
修改C++的main函数:
#include <iostream> #include <cstdio> // 需包含头文件 #define VAR_NUM 1000 using namespace std; void read_vars(int* vars){ char buf; int chk; for(int i=0; i<VAR_NUM; i++){ chk = fread(&buf, sizeof(char), 1, stdin); std::cout << (int)(unsigned char)buf << "(" << chk <<") "; vars[i] = (int)(unsigned char)buf; if(chk==0){ if(feof(stdin)) std::cout << "[EOF] "; if(ferror(stdin)) std::cout << "[ERROR] "; } } std::cout << endl; return; } int main(){ setvbuf(stdin, NULL, _IONBF, 0); // 设置stdin为无缓冲 int* vars = (int*) malloc(VAR_NUM*sizeof(int)); for(int i=0; i<VAR_NUM; i++) vars[i] = 0; read_vars(vars); free(vars); // 补充内存释放 return 0; }
方法3:一次性读取全部字节
逐字节读取在Windows管道下易出现状态异常,改为一次性读取所有1000字节,减少IO操作次数:
修改C++的read_vars函数:
void read_vars(int* vars){ char buf[VAR_NUM]; size_t chk = fread(buf, sizeof(char), VAR_NUM, stdin); for(int i=0; i<VAR_NUM; i++){ if(i < chk){ vars[i] = (int)(unsigned char)buf[i]; std::cout << vars[i] << "(1) "; } else { vars[i] = 0; std::cout << 0 << "(0) [EOF] "; } } std::cout << endl; return; }
内容的提问来源于stack exchange,提问作者jrizos
相关产品推荐
相关产品推荐

