【发布时间】: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 就是这样!非常感谢。如果你想写你的评论作为答案,我会接受。