目的是通过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编程,不尽之处,敬请指正。