python与Geant4的socket通信

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

上一篇:单调队列。


下一篇:1088 旅行问题(单调队列优化)