【问题标题】:Using TCP for Inter Process Communication(IPC) with fortran在 fortran 中使用 TCP 进行进程间通信 (IPC)
【发布时间】:2014-09-21 04:49:51
【问题描述】:

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

ie:模拟进程(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

我知道问题出在“本地主机”中:

sockfd=ClientSocket("localhost",port)

但我终其一生都无法弄清楚原因。我还尝试使用计算机的内部 IP 地址和公共 IP 地址并尝试使用多台机器(在一台机器上运行服务器,在另一台机器上运行客户端,同时通过对等网络运行)并且总是得到相同的错误.有谁知道发生了什么(或者如果您认为我的 fortran IPC 有更好的解决方案,也可以给我)?

谢谢! 安德鲁

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

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

名称应该清楚地表明哪个代码与哪个代码搭配。

【问题讨论】:

  • 我可能会尝试使用 MPI 解决这个问题,而不是自制 TCP 客户端/服务器架构。
  • 谢谢你的建议,我现在看看。
  • @Stefan 就是这样!非常感谢。如果你想写你的评论作为答案,我会接受。

标签: c sockets tcp fortran ipc


【解决方案1】:

问题在于 C 和 Fortran 对字符串的处理方式不同。

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

sockfd=ClientSocket("localhost"//C_NULL_CHAR, port)

其中C_NULL_CHAR 在ISO_C_BINDING 模块中定义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-25
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    • 2011-08-28
    • 2012-04-01
    • 2016-09-11
    • 1970-01-01
    相关资源
    最近更新 更多