Winsock?

Winsock?

Steve, I saw a comment you made on c.l.f about a winsock module in IVF. Where can I find info about this? The docs don't seem to have anything.

Thanks
Gib

17 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

It's one of the Win32 modules. Actually, two of them: wsock32.mod and ws2_32.mod. You can find the sources to these in the compiler's Include folder. We don't have any samples that use these.

Retired 12/31/2016

Quoting - gib
Steve, I saw a comment you made on c.l.f about a winsock module in IVF. Where can I find info about this? The docs don't seem to have anything.

Thanks
Gib

Gib,
What do you want to do here? I have written a set of Winsock routines for ethernet communications, which use the Win32 API functions in WS2_32.f90 (interface module included with IVF), and allow you to open a socket to an IP address and read and write packets.

Quoting - Paul Curtis

Gib,
What do you want to do here? I have written a set of Winsock routines for ethernet communications, which use the Win32 API functions in WS2_32.f90 (interface module included with IVF), and allow you to open a socket to an IP address and read and write packets.

Hi Paul,
I'm looking into possible ways of communicating data asynchronously between an executing Fortran program and a Python program that will handle the GUI duties. For portability I've decided to adopt the approach where the Fortran is built as a library (DLL or .so), and input data is passed in files. I'm not sure what method would be best for displaying on-the-fly results in the Python master program, but using sockets is one option. If this seems to be a good way to go I would be very interested in your code.

This might be a good place to ask whether someone thinks another method would be preferable, e.g. writing and reading from a file.

I like the flexibility of using sockets. Looking ahead, the socket approach would enable server-based execution of the Fortran engine. The Python could be distributed to users, and the model could be run on a powerful multicore server. This assumes that I'm able to interest others in using the model, of course.

Quoting - Steve Lionel (Intel)

It's one of the Win32 modules. Actually, two of them: wsock32.mod and ws2_32.mod. You can find the sources to these in the compiler's Include folder. We don't have any samples that use these.

Ah, I see. Thanks Steve.

Best Reply

Quoting - gib

Hi Paul,
I'm looking into possible ways of communicating data asynchronously between an executing Fortran program and a Python program that will handle the GUI duties. For portability I've decided to adopt the approach where the Fortran is built as a library (DLL or .so), and input data is passed in files. I'm not sure what method would be best for displaying on-the-fly results in the Python master program, but using sockets is one option. If this seems to be a good way to go I would be very interested in your code.

This might be a good place to ask whether someone thinks another method would be preferable, e.g. writing and reading from a file.

I like the flexibility of using sockets. Looking ahead, the socket approach would enable server-based execution of the Fortran engine. The Python could be distributed to users, and the model could be run on a powerful multicore server. This assumes that I'm able to interest others in using the model, of course.

The att. file has been carved out of a large program, and hastily modified to be roughly stand-alone with dependences on other objects and code hopefully eliminated; at any rate, this may serve as a quick guide on setting up socket-based communications (it does work extremely well). This module uses ReadFile/WriteFile once a socket has been set up, and it may be that the more specialized functions WSARecv() and WSASend() might also work, maybe better.

Although you didn't ask, your stated project outline leads me to suggest that you can easily build complete Win32 gui features entirely in Fortran, thereby eliminating an architectural approach which looks to be hugely complex right from the start. Good luck.

Attachments: 

AttachmentSize
Downloadapplication/octet-stream winsock_example.f9014.36 KB

Quoting - Paul Curtis
The att. file has been carved out of a large program, and hastily modified to be roughly stand-alone with dependences on other objects and code hopefully eliminated; at any rate, this may serve as a quick guide on setting up socket-based communications (it does work extremely well). This module uses ReadFile/WriteFile once a socket has been set up, and it may be that the more specialized functions WSARecv() and WSASend() might also work, maybe better.

Although you didn't ask, your stated project outline leads me to suggest that you can easily build complete Win32 gui features entirely in Fortran, thereby eliminating an architectural approach which looks to be hugely complex right from the start. Good luck.

Thanks a lot Paul, that's great!

In reply to your comment, if I expect others to use this program (and that's the main reason for creating a GUI) I can't stay in the Windows world. Most biologists, my target audience, use Macs. I am trying to plot the course ahead such that the code will be completely platform-neutral, well, able to run on Windows, Linux and OSX. Python runs everywhere, and then there's gfortran or G95 for places where IVF code can't go.

Quoting - Paul Curtis

The att. file has been carved out of a large program, and hastily modified to be roughly stand-alone with dependences on other objects and code hopefully eliminated; at any rate, this may serve as a quick guide on setting up socket-based communications (it does work extremely well). This module uses ReadFile/WriteFile once a socket has been set up, and it may be that the more specialized functions WSARecv() and WSASend() might also work, maybe better.

Although you didn't ask, your stated project outline leads me to suggest that you can easily build complete Win32 gui features entirely in Fortran, thereby eliminating an architectural approach which looks to be hugely complex right from the start. Good luck.

Hi Paul,
After fixing a couple of typos and adding 'use ifwin' I got rid of most of the compilation errors. But I still get these messages:
1>D:FortranCodewinsock_example.f90(81): error #6405: The same named entity from different modules and/or program units cannot be referenced. [WSASTARTUP]
1>D:FortranCodewinsock_example.f90(86): error #6405: The same named entity from different modules and/or program units cannot be referenced. [WSACLEANUP]
1>D:FortranCodewinsock_example.f90(125): error #6405: The same named entity from different modules and/or program units cannot be referenced. [SOCKET]
1>D:FortranCodewinsock_example.f90(127): error #6405: The same named entity from different modules and/or program units cannot be referenced. [SOCKET]
1>D:FortranCodewinsock_example.f90(136): error #6405: The same named entity from different modules and/or program units cannot be referenced. [SETSOCKOPT]
1>D:FortranCodewinsock_example.f90(172): error #6405: The same named entity from different modules and/or program units cannot be referenced. [HTONS]
1>D:FortranCodewinsock_example.f90(175): error #6405: The same named entity from different modules and/or program units cannot be referenced. [CONNECT]
1>D:FortranCodewinsock_example.f90(202): error #6405: The same named entity from different modules and/or program units cannot be referenced. [SHUTDOWN]
1>D:FortranCodewinsock_example.f90(203): error #6405: The same named entity from different modules and/or program units cannot be referenced. [CLOSESOCKET]
1>D:FortranCodewinsock_example.f90(328): error #6405: The same named entity from different modules and/or program units cannot be referenced. [SHUTDOWN]
1>D:FortranCodewinsock_example.f90(330): error #6405: The same named entity from different modules and/or program units cannot be referenced. [CLOSESOCKET]
1>D:FortranCodewinsock_example.f90(346): error #6405: The same named entity from different modules and/or program units cannot be referenced. [WSAGETLASTERROR]

I don't know what this means. Perhaps I should be doing something other than using ifwin. Is there a build setting that I'm missing, some library to link?

IFWIN is just a set of USE statements for the various Win32 interface modules, which track their Windows counterparts. In this case (as the code says) you need to USE ws2_32, and not wsock32 which is part of the IFWIN collection. Here is what I do in the main program from which this winsock module was extracted:

!   these are the contents of ifwin, omitting wsock32;
!   the module winsock.f90 USEs ws2_32.f90 instead,
!   and we thus need to avoid conflicts with wsock32.f90
USE advapi32
USE comdlg32
USE ifwbase
USE gdi32
USE kernel32
!use lz32
!use mpr      ! WNet connection APIs, not used by this program
USE shell32
USE user32
!use version
!use winmm    ! Windows multimedia APIs, not used by this program
USE winspool

!   Win32 types and defines
USE ifwinty

Quoting - Paul Curtis
IFWIN is just a set of USE statements for the various Win32 interface modules, which track their Windows counterparts. In this case (as the code says) you need to USE ws2_32, and not wsock32 which is part of the IFWIN collection. Here is what I do in the main program from which this winsock module was extracted:

!   these are the contents of ifwin, omitting wsock32;
!   the module winsock.f90 USEs ws2_32.f90 instead,
!   and we thus need to avoid conflicts with wsock32.f90
USE advapi32
USE comdlg32
USE ifwbase
USE gdi32
USE kernel32
!use lz32
!use mpr      ! WNet connection APIs, not used by this program
USE shell32
USE user32
!use version
!use winmm    ! Windows multimedia APIs, not used by this program
USE winspool

!   Win32 types and defines
USE ifwinty

Thanks, that works. I'm very unfamiliar with this W32 stuff.

Cheers
Gib

Quoting - Paul Curtis
IFWIN is just a set of USE statements for the various Win32 interface modules, which track their Windows counterparts. In this case (as the code says) you need to USE ws2_32, and not wsock32 which is part of the IFWIN collection. Here is what I do in the main program from which this winsock module was extracted:

!   these are the contents of ifwin, omitting wsock32;
!   the module winsock.f90 USEs ws2_32.f90 instead,
!   and we thus need to avoid conflicts with wsock32.f90
USE advapi32
USE comdlg32
USE ifwbase
USE gdi32
USE kernel32
!use lz32
!use mpr      ! WNet connection APIs, not used by this program
USE shell32
USE user32
!use version
!use winmm    ! Windows multimedia APIs, not used by this program
USE winspool

!   Win32 types and defines
USE ifwinty

Sorry to bother you, Paul, but the info available for winsock and IVF is very limited, as I'm sure you discovered. I haven't been able to figure out how to supply the host address wp%ip_addr:
TYPE(T_IN_ADDR) :: ip_addr ! server IP address u_long
I presume this involves gethostbyname() or gethostbyaddr(), but all my attempts with these have failed to return anything other than 0. Can you show some code that does this?

Thanks
Gib

I found inet_addr(), which I believe does what I want, since I now can call Set_Winsock_Port() and get a handle, so presumably I have created a UDP client socket. For some reason it doesn't work get with the TCP protocol.

Quoting - gib

Sorry to bother you, Paul, but the info available for winsock and IVF is very limited, as I'm sure you discovered. I haven't been able to figure out how to supply the host address wp%ip_addr:
TYPE(T_IN_ADDR) :: ip_addr ! server IP address u_long
I presume this involves gethostbyname() or gethostbyaddr(), but all my attempts with these have failed to return anything other than 0. Can you show some code that does this?

Thanks
Gib

I found inet_addr(), which I believe does what I want, since I now can call Set_Winsock_Port() and get a handle, so presumably I have created a UDP client socket. For some reason it doesn't work get with the TCP protocol.

The following utility function makes clear how ip address elements are packaged into an I*4:

INTEGER FUNCTION ip_addr_to_string (ipa, string) RESULT (nc)
    IMPLICIT NONE
    INTEGER, INTENT(IN)             :: ipa
    CHARACTER(LEN=*), INTENT(OUT)   :: string
    
    WRITE (string, '(3(I3,"."),I3)')       IAND(ipa, Z'000000FF'),       &
                                     ISHFT(IAND(ipa, Z'0000FF00'),  -8), &
                                     ISHFT(IAND(ipa, Z'00FF0000'), -16), &
                                     ISHFT(IAND(ipa, Z'FF000000'), -24)
    nc = leftpack(string)
END FUNCTION ip_addr_to_string

Here are some wrapper functions to access an ip address control in a dialog:

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! IP Address control functions
!

SUBROUTINE IPAddressSetAddress (hwnd, controlId, addr)
    IMPLICIT NONE
    INTEGER, INTENT(IN)                 :: hwnd
    INTEGER, INTENT(IN)                 :: controlId
    TYPE(T_IN_ADDR),INTENT(INOUT)       :: addr
    INTEGER						        :: j
    
	j = SendControlMessage (hwnd, controlId, IPM_SETADDRESS, 0, addr%s_addr)

END SUBROUTINE IPAddressSetAddress


SUBROUTINE IPAddressGetAddress (hwnd, controlId, addr)
    IMPLICIT NONE
    INTEGER(HANDLE), INTENT(IN)         :: hwnd
    INTEGER, INTENT(IN)                 :: controlId
    TYPE(T_IN_ADDR), INTENT(INOUT)      :: addr
    INTEGER						        :: j
    
	j = SendControlMessage (hwnd, controlId, IPM_GETADDRESS, 0, LOC(addr%s_addr))


Also, on input you need to tranpose the integer format:

!   transpose the little-endian intel format to big-endian ip format
inad%s_addr = ntohl(ip_addr%s_addr)

Quoting - Paul Curtis

The following utility function makes clear how ip address elements are packaged into an I*4:

INTEGER FUNCTION ip_addr_to_string (ipa, string) RESULT (nc)
    IMPLICIT NONE
    INTEGER, INTENT(IN)             :: ipa
    CHARACTER(LEN=*), INTENT(OUT)   :: string

    WRITE (string, '(3(I3,"."),I3)')       IAND(ipa, Z'000000FF'),       &
                                     ISHFT(IAND(ipa, Z'0000FF00'),  -8), &
                                     ISHFT(IAND(ipa, Z'00FF0000'), -16), &
                                     ISHFT(IAND(ipa, Z'FF000000'), -24)
    nc = leftpack(string)
END FUNCTION ip_addr_to_string

Here are some wrapper functions to access an ip address control in a dialog:

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! IP Address control functions
!

SUBROUTINE IPAddressSetAddress (hwnd, controlId, addr)
    IMPLICIT NONE
    INTEGER, INTENT(IN)                 :: hwnd
    INTEGER, INTENT(IN)                 :: controlId
    TYPE(T_IN_ADDR),INTENT(INOUT)       :: addr
    INTEGER						        :: j

	j = SendControlMessage (hwnd, controlId, IPM_SETADDRESS, 0, addr%s_addr)

END SUBROUTINE IPAddressSetAddress


SUBROUTINE IPAddressGetAddress (hwnd, controlId, addr)
    IMPLICIT NONE
    INTEGER(HANDLE), INTENT(IN)         :: hwnd
    INTEGER, INTENT(IN)                 :: controlId
    TYPE(T_IN_ADDR), INTENT(INOUT)      :: addr
    INTEGER						        :: j

	j = SendControlMessage (hwnd, controlId, IPM_GETADDRESS, 0, LOC(addr%s_addr))


Also, on input you need to tranpose the integer format:

!   transpose the little-endian intel format to big-endian ip format
inad%s_addr = ntohl(ip_addr%s_addr)

Thanks Paul. I have the TCP protocol half working. I can send to a server, but I can't receive. I'm running a simple Python server program, which can communicate successfully back and forth with a Python client program.

The connection is established, and the Fortran client program loops on winsock_receive(). The server then sends a message, but the client doesn't get it.

ReadFile() returns 0
WSA_error() returns ERROR_IO_PENDING
WaitForSingleObject() returns WAIT_TIMEOUT

I tried the new code with WSARecv(), but that immediately gave a very large nrcv (before any message was sent from the server).

Any ideas?

Gib,
My code

  1. runs within a communications thread which is separate from the main program thread, so neither loads the other (actually I typically have many comm threads going simultaneously);
  2. is designed for query/response interchanges with devices which "speak only when spoken to", and do so promptly (ie, will not wait for you to wheel your chair over to the other computer and type something in);
  3. presumes that the socket stays open after a query has been sent, waiting for a reply to the same socket, which is then closed when the interchange completes; the default wait time is 1000ms, which can be increased if your device has a really slow response.

If the socket is open and the response arrives before you get to ReadFile, the response will be buffered by the Windows network layer (probably at least up to 8Kb), so ReadFile would have no trouble recovering the message in that case.

BTW, you first want to make sure your host can ping the ip of your target; if a basic ping times out you have a network problem. HTH

Quoting - Paul Curtis
Gib,
My code

  1. runs within a communications thread which is separate from the main program thread, so neither loads the other (actually I typically have many comm threads going simultaneously);
  2. is designed for query/response interchanges with devices which "speak only when spoken to", and do so promptly (ie, will not wait for you to wheel your chair over to the other computer and type something in);
  3. presumes that the socket stays open after a query has been sent, waiting for a reply to the same socket, which is then closed when the interchange completes; the default wait time is 1000ms, which can be increased if your device has a really slow response.

If the socket is open and the response arrives before you get to ReadFile, the response will be buffered by the Windows network layer (probably at least up to 8Kb), so ReadFile would have no trouble recovering the message in that case.

BTW, you first want to make sure your host can ping the ip of your target; if a basic ping times out you have a network problem. HTH

I'm seeing some interesting behaviour. First, I'm running server and client on the same machine (which is unloaded), using 127.0.0.1, so there is no issue of latency.

I've set up a Python server that just echoes back received messages. Immediately after a connection is made it sends a greeting message, then it loops receiving messages and sending them back. After connecting the client is in a loop, first receiving a message, then sending a string entered at the console. This works fine. But if there is a delay before the first message is sent from the server, and WaitForSingleObject() returns with WAIT_TIMEOUT, subsequent calls to winsock_receive() all fail in the same way, i.e. the greeting message is never received. It seems that possibly something needs to be reset after that first time winsock_receive() fails to get a message.

I sense that I'm very close to getting this working.

Any ideas?

I think I've cracked it. If ReadFile() times out, this pending asynchronous I/O operation must be cancelled before another attempt is made. This is done with cancelIo():

CASE (WAIT_TIMEOUT)
mode = 4
nc = cancelIo(wp%handle)

With this addition all seems to be working.

Thanks very much, Paul, you've saved me a tremendous amount of effort.

Gib

Quoting - gib

CASE (WAIT_TIMEOUT)
mode = 4
nc = cancelIo(wp%handle)

That's really interesting. Strangely, I have never had that sort of hangup, but reading the chat on CancelIO() indicates this is exactly what is needed to recover after a timeout. I looked through many examples of winsock setups in C while devising my F90 version, and somehow never saw that function imbedded in the timeout response. Thanks for your efforts.

Dear all,

Is there any complete example about using winsock in IVF?

I need to the server/client system with the client sending the calculation information and the server listen to the message and then launch some software (for example, the Ansoft Maxwell) to do the calculation, and then send results back to the client.

Thanks,
Zhanghong Tang

Leave a Comment

Please sign in to add a comment. Not a member? Join today