目的是通过socket实现python和Geant4应用的通信,把Geant的模拟数据传送给python。在下面的试验中python作为服务端,Geant4作为客户端,运行环境为windows+vc2015。
一、c++客户端
PNClient.hh
#ifndef PNClient_H #define PNClient_H 1 #include#include #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" #includePNClient::~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, ' ', 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#include 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, ' ', 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, ' ', 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编程,不尽之处,敬请指正。



