目的是通过socket实现python和Geant4应用的通信,把Geant的模拟数据传送给python。在下面的试验中python作为服务端,Geant4作为客户端,运行环境为windows+vc2015。
一、c++客户端
PNClient.hh
#ifndef PNClient_H #define PNClient_H 1 #include <string> #include <Winsock2.h> #pragma comment(lib,"ws2_32.lib") #pragma warning(disable:4996) class PNClient { public: PNClient(); ~PNClient(); void Close(); void SendLine(std::string); std::string ReceiveLine(); int Send(char*, int); int Receive(char*); private: SOCKET s_; static void Start(); static void End(); }; #endif
PNClient.cc
#include "PNClient.hh" #include <iostream> PNClient::~PNClient() { End(); } void PNClient::Start() { WSADATA info; if (WSAStartup(MAKEWORD(2,2), &info)) { throw "Could not start WSA"; } } PNClient::PNClient():s_(0) { Start(); s_ = socket(AF_INET,SOCK_STREAM,0); if (s_ == INVALID_SOCKET) { throw "INVALID_SOCKET"; } std::string error; sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(8080); addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); memset(&(addr.sin_zero), 0, 8); if (::connect(s_, (sockaddr *) &addr, sizeof(sockaddr))) { error = strerror(WSAGetLastError()); throw error; } } std::string PNClient::ReceiveLine() { std::string ret; while (1) { char r; if(recv(s_, &r, 1, 0) <0) { return ""; } ret += r; if (r == '\n') return ret; } } void PNClient::SendLine(std::string s) { s += '\n'; send(s_,s.c_str(),s.length(),0); } int PNClient::Send(char *buf, int len) { if (send(s_, buf, 64, 0) < 0) { printf("send failed!\n"); len = -1; } if (len > 64) { printf("64 bytes has sent!"); len = 64; } return len; } int PNClient::Receive(char *recvbuf) { int len; memset(recvbuf, '\0', 64); len = recv(s_, recvbuf, 63, 0); if(len < 0) { printf("recv failed!\n"); len = -1; } return len; } void PNClient::End() { WSACleanup(); }
二、RunAction
PNRunAction.hh
#ifndef PNRunAction_h #define PNRunAction_h 1 #include "G4UserRunAction.hh" #include "globals.hh" class G4Run; class PNClient; class PNRunAction : public G4UserRunAction { public: PNRunAction(); virtual ~PNRunAction(); public: virtual void BeginOfRunAction(const G4Run*); virtual void EndOfRunAction(const G4Run*); PNClient* GetSocket() { return ps; } private: PNClient* ps; }; #endif
PNRunAction.cc
#include "PNRunAction.hh" #include "G4Run.hh" #include "G4RunManager.hh" #include "PNClient.hh" using namespace std; PNRunAction::PNRunAction() { ps = new PNClient(); } PNRunAction::~PNRunAction() { } void PNRunAction::BeginOfRunAction(const G4Run* aRun) { G4RunManager::GetRunManager()->SetPrintProgress(100); G4cout << "Run " << aRun -> GetRunID() << " starts ..." << G4endl; G4cout << ps->ReceiveLine(); string HeadLine = "Run Begin"; ps->SendLine(HeadLine); G4cout << ps->ReceiveLine(); } void PNRunAction::EndOfRunAction(const G4Run* aRun) { G4cout << " End of Run: " << aRun -> GetRunID() << G4endl; ps->SendLine("Run End"); G4cout << ps->ReceiveLine() << G4endl; delete ps; }
三、StepAction
PNSteppingAction.hh
#ifndef PNSteppingAction_h #define PNSteppingAction_h 1 #include "G4UserSteppingAction.hh" #include "globals.hh" class PNClient; class PNRunAction; struct Info { char name[32]; G4double px; G4double py; G4double pz; G4double eDep; }; class PNSteppingAction : public G4UserSteppingAction { public: PNSteppingAction(PNRunAction*); ~PNSteppingAction(); void UserSteppingAction(const G4Step*); private: PNClient* ps; }; #endif
PNSteppingAction.cc
#include "PNSteppingAction.hh" #include "G4RunManager.hh" #include "G4Track.hh" #include "G4TrackVector.hh" #include "G4TrackStatus.hh" #include "G4Step.hh" #include "G4StepPoint.hh" #include "G4ParticleDefinition.hh" #include "G4ParticleTypes.hh" #include "G4LogicalVolume.hh" #include "G4VPhysicalVolume.hh" #include "G4SystemOfUnits.hh" #include "PNClient.hh" #include "PNRunAction.hh" //#include <sstream> #include <string> PNSteppingAction::PNSteppingAction(PNRunAction* run) { ps = run->GetSocket(); } PNSteppingAction::~PNSteppingAction() { } void PNSteppingAction::UserSteppingAction(const G4Step* aStep) { G4Track* aTrack = aStep->GetTrack(); G4String Vol = aTrack->GetVolume()->GetName(); G4String name = aTrack->GetDefinition()->GetParticleName(); G4ThreeVector Pos = aTrack->GetPosition(); G4ThreeVector Dir = aTrack->GetMomentumDirection(); G4double eKin = aTrack->GetKineticEnergy(); G4double gTime = aTrack->GetGlobalTime(); Info info; memset(&info, '\0', 32); strcpy(info.name, name.c_str()); info.px = 0.1; //Pos.x(); info.py = 0.2; //Pos.y(); info.pz = 0.3; //Pos.z(); info.eDep = 0.4; //eKin; char buf[64]; //memset(buf, '\0', 64); memcpy(buf, &info, 64); ps->Send(buf, 64); }
python服务端
import socket from _thread import * from struct import * def PrintData(data): data0 = data[0:32] name = data0.decode('ASCII', 'ignore') #print(len(data)) data1 = data[32:64] #print(type(info)) #print(len(info)) print(name[0:8], unpack('dddd', data1)) def threaded_client(connection, t_count): connection.send(str.encode('Welcome to the python Server!\n')) while True: data = connection.recv(64) #if not data: # break if b'Begin' in data: connection.send(str.encode('Ready!\n','utf-8')) elif b'End' in data: connection.send(str.encode('Ok!\n')) print('Ok!\n') break else: PrintData(data) connection.close() if __name__ == '__main__': ServerSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = '127.0.0.1' port = 8080 try: ServerSocket.bind((host, port)) except socket.error as e: print(str(e)) print('Waiting for a Connection..') ServerSocket.listen(5) ThreadCount = 0 while True: Client, address = ServerSocket.accept() print('Connected to: ' + address[0] + ':' + str(address[1])) start_new_thread(threaded_client, (Client, ThreadCount)) ThreadCount += 1 print('Thread Number: ' + str(ThreadCount)) ServerSocket.close() input("end")
这里没有贴出Geant4主程序及其它必须的类实现如几何构建。首先编译Geant4应用代码,生成可执行文件。先执行python服务端,然后运行Geant4应用程序。上述代码实现了RunAction和python进程的交互,以及把StepAtction的数据包装成一个数据结构通过socket传输到python进程。
如在linux环境实现需要改写客户端代码,也许要考虑多线程安全。初次接触socket编程,不尽之处,敬请指正。