使用TCP与Fortran进行进程间通信(IPC)

时间:2014-07-29 17:42:45

标签: c sockets tcp fortran ipc

我正在努力创建一种让多个Fortran进程相互通信的方法。这将用于模拟,其中一台机器正在运行模拟过程,而另一台机器(或可能是机器集群)将为模拟过程生成合成数据。

即:模拟过程(sp)向生成过程(gp)请求一条信息。 gp要么找到所请求的信息,要么创建它并将其返回到sp。

这两个过程都非常密集,这就是为什么它们将在多台机器之间分配的原因。

无论如何,在做了一些研究后,我能为这个IPC提出的最好的方法是使用TCP和IP。在做了一些研究之后,我能够提出以下代码(取自here):

模块

MODULE MSockets
   ! Interface to libmsock
   ! A library for TCP/IP client-server applications on Unix by Muhammad A Muquit
   ! http://www.muquit.com/muquit/software/libmsock/libmsock.html
   USE ISO_C_BINDING
   IMPLICIT NONE
   PUBLIC

   INTEGER, PARAMETER :: CC_SIZE_T=C_INT

   INTERFACE
      ! Interfaces for the main functions

      ! int close(int fildes)
      ! This one is not in libmsock technically but is needed to close sockets:
      FUNCTION CloseSocket(fildes) BIND(C,NAME="close")  RESULT(error)
         IMPORT
         INTEGER(C_INT), VALUE :: fildes
         INTEGER(C_INT) :: error
      END FUNCTION          
      ! int ServerSocket(u_short port,int max_servers);
      FUNCTION ServerSocket(port,max_servers) BIND(C,NAME="ServerSocket")  RESULT(sockfd)
         IMPORT
         INTEGER(C_SHORT), VALUE :: port
         INTEGER(C_INT), VALUE :: max_servers
         INTEGER(C_INT) :: sockfd
      END FUNCTION
      ! int ClientSocket(char *netaddress,u_short port);
      FUNCTION ClientSocket(netaddress,port) BIND(C,NAME="ClientSocket")  RESULT(sockfd)
         IMPORT
         CHARACTER(C_CHAR), DIMENSION(*), INTENT(IN) :: netaddress
         INTEGER(C_SHORT), VALUE :: port
         INTEGER(C_INT) :: sockfd
      END FUNCTION
      ! int sockGets(int sockfd,char *str,size_t count);
      FUNCTION sockGets(sockfd,str,count) BIND(C,NAME="sockGets")  RESULT(length)
         IMPORT
         INTEGER(C_INT), VALUE :: sockfd
         CHARACTER(C_CHAR), DIMENSION(*), INTENT(IN) :: str
         INTEGER(CC_SIZE_T), VALUE :: count
         INTEGER(C_INT) :: length ! Bytes read
      END FUNCTION
      ! int sockRead(int sockfd,char *str,size_t count);
      FUNCTION sockRead(sockfd,str,count) BIND(C,NAME="sockRead")  RESULT(error)
         IMPORT
         INTEGER(C_INT), VALUE :: sockfd
         INTEGER(CC_SIZE_T), VALUE :: count
         CHARACTER(C_CHAR), DIMENSION(count), INTENT(OUT) :: str
         INTEGER(C_INT) :: error
      END FUNCTION
      ! int sockPuts(int sockfd,char *str);
      FUNCTION sockPuts(sockfd,str) BIND(C,NAME="sockPuts")  RESULT(error)
         IMPORT
         INTEGER(C_INT), VALUE :: sockfd
         CHARACTER(C_CHAR), DIMENSION(*), INTENT(IN) :: str ! NULL terminated
         INTEGER(C_INT) :: error
      END FUNCTION
      ! int sockWrite(int sockfd,char *str,size_t count);
      FUNCTION sockWrite(sockfd,str,count) BIND(C,NAME="sockWrite")  RESULT(error)
         IMPORT
         INTEGER(C_INT), VALUE :: sockfd
         INTEGER(CC_SIZE_T), VALUE :: count
         CHARACTER(C_CHAR), DIMENSION(count), INTENT(IN) :: str
         INTEGER(C_INT) :: error
      END FUNCTION
   END INTERFACE

END MODULE

服务器程序

PROGRAM MSockets_Server
   USE ISO_C_BINDING
   USE MSockets
   IMPLICIT NONE

   INTEGER(C_SHORT) :: port
   INTEGER(C_INT) :: sockfd
   CHARACTER(KIND=C_CHAR, LEN=1024) :: buffer
   INTEGER(CC_SIZE_T) :: count
   INTEGER(C_INT) :: length, error

   port=HUGE(port) ! Most likely unused port
   sockfd=ServerSocket(port,2_c_int) ! It will return only once a connection is made
   IF(sockfd<0) STOP "Failed to open server socket"

   WRITE(*,*) "Client connected!"
   DO
      length=sockGets(sockfd,buffer,INT(LEN(buffer),CC_SIZE_T))
      IF(length<0) EXIT
      IF(length>0) WRITE(*,*) "Client said: ", buffer(1:length)
   END DO
   WRITE(*,*) "Client disconnected"

   error=CloseSocket(sockfd)
   IF(error<0) STOP "Failed to close server socket"

END PROGRAM

客户计划

PROGRAM MSockets_Client
   USE ISO_C_BINDING
   USE MSockets
   IMPLICIT NONE

   INTEGER(C_SHORT) :: port
   INTEGER(C_INT) :: sockfd
   CHARACTER(KIND=C_CHAR, LEN=1024) :: buffer
   INTEGER(CC_SIZE_T) :: count
   INTEGER(C_INT) :: length, error

   port=HUGE(port) ! Most likely unused port
   sockfd=ClientSocket("localhost",port)
   IF(sockfd<0) STOP "Failed to open client socket"

   WRITE(*,*) "Enter what you want to tell the server:"
   DO
      READ(*,"(A)") buffer
      IF(buffer=="quit") EXIT ! Last input
      error=sockPuts(sockfd,TRIM(buffer)//C_NEW_LINE)
      IF(error<0) STOP "Server died!"
   END DO

   error=CloseSocket(sockfd)
   IF(sockfd<0) STOP "Failed to close client socket"   

END PROGRAM

这些程序依赖于从here获取的c库以进行TCP / IP通信。一切都很好,我可以成功启动服务器;但是,当我尝试启动客户端时,我收到以下错误:

ClientSocket(): Invalid network address
STOP Failed to open client socket

我知道这个问题来自&#34; localhost&#34;在:

sockfd=ClientSocket("localhost",port)

但我不能为我的生活找出原因。我也尝试使用计算机的内部IP地址并使用公共IP地址并尝试使用多台计算机(在一台对等网络上运行时在一台机器上运行服务器,在另一台机器上运行客户机)并始终得到相同的错误。有没有人知道最新情况(或者如果你认为我的fortran IPC有更好的解决方案也给我这个)?

谢谢! 安德鲁

另外,对于它的价值,我使用gfortran在Mac OSX 10.9上运行它。我用来编译的命令是:

gfortran -c sockets.f90
gfortran client.f90 -o client.x -L"../../../libmsock/libmsock/" -lmsock -g
gfortran server.f90 -o server.x -L"../../../libmsock/libmsock/" -lmsock -g

其中名称应该清楚地表明哪个代码与哪个代码相关。

1 个答案:

答案 0 :(得分:2)

问题是C和Fortran中字符串的不同处理。

您将"localhost"作为Fortran字符串传递,其结尾由固定(在本例中为隐含)长度决定。在C中,字符串必须以NUL结尾。这可以通过编写

来实现
sockfd=ClientSocket("localhost"//C_NULL_CHAR, port)

其中C_NULL_CHARISO_C_BINDING模块中定义。