ubuntu

Ubuntu上Fortran网络编程怎么操作

小樊
31
2025-12-28 03:32:28
栏目: 智能运维

Ubuntu 上 Fortran 网络编程实操指南

一、环境准备与总体思路

二、方式一 原生套接字 TCP 最小示例(ISO_C_BINDING 调用 C API)

program server
  use, intrinsic :: iso_c_binding
  implicit none
  integer(c_int), parameter :: AF_INET = 2, SOCK_STREAM = 1, INADDR_ANY = 0
  integer(c_int), parameter :: PORT = 12345
  integer(c_int) :: server_fd, client_fd, n
  type(c_ptr) :: addr_ptr
  character(len=1), target :: addr_buf(16 + 2*4)  ! 简化:容纳 sockaddr_in
  integer(c_socklen_t) :: addr_len
  character(len=1024) :: buf

  interface
    function socket(domain, type, protocol) bind(c, name="socket")
      import c_int
      integer(c_int), value :: domain, type, protocol
      integer(c_int) :: socket
    end function socket
    function bind(sockfd, addr, addrlen) bind(c, name="bind")
      import c_int, c_ptr, c_socklen_t
      integer(c_int), value :: sockfd
      type(c_ptr), value :: addr
      integer(c_socklen_t), value :: addrlen
      integer(c_int) :: bind
    end function bind
    function listen(sockfd, backlog) bind(c, name="listen")
      import c_int
      integer(c_int), value :: sockfd, backlog
      integer(c_int) :: listen
    end function listen
    function accept(sockfd, addr, addrlen) bind(c, name="accept")
      import c_int, c_ptr, c_socklen_t
      integer(c_int), value :: sockfd
      type(c_ptr), value :: addr
      integer(c_socklen_t), intent(inout) :: addrlen
      integer(c_int) :: accept
    end function accept
    function recv(sockfd, buf, len, flags) bind(c, name="recv")
      import c_int, c_void, c_socklen_t
      integer(c_int), value :: sockfd
      type(c_ptr), value :: buf
      integer(c_socklen_t), value :: len
      integer(c_int), value :: flags
      integer(c_int) :: recv
    end function recv
    function close(fd) bind(c, name="close")
      import c_int
      integer(c_int), value :: fd
      integer(c_int) :: close
    end function close
  end interface

  ! 创建套接字
  server_fd = socket(AF_INET, SOCK_STREAM, 0_c_int)
  if (server_fd < 0) stop 'socket failed'

  ! 准备地址(简化:直接把 sockaddr_in 放在 addr_buf 中,端口用 htons)
  addr_buf = 0
  call set_sin_family(addr_buf, AF_INET)
  call set_sin_port  (addr_buf, htons(PORT))
  call set_sin_addr  (addr_buf, INADDR_ANY)

  addr_ptr = c_loc(addr_buf)
  addr_len = 16 + 2*4  ! sizeof(struct sockaddr_in)

  ! 绑定、监听、接收
  if (bind(server_fd, addr_ptr, addr_len) < 0) stop 'bind failed'
  if (listen(server_fd, 5_c_int) < 0) stop 'listen failed'
  print '("Server listening on port ", I0)', PORT

  client_fd = accept(server_fd, addr_ptr, addr_len)
  if (client_fd < 0) stop 'accept failed'
  print *, 'Client connected'

  n = recv(client_fd, c_loc(buf), int(size(buf), c_socklen_t), 0_c_int)
  if (n > 0) print '("Received: ", A)', trim(buf(:n))

  call close(client_fd)
  call close(server_fd)
contains
  subroutine set_sin_family(buf, fam)
    character(len=1), intent(inout) :: buf(*)
    integer(c_int), intent(in) :: fam
    buf(1:4) = transfer(fam, buf(1:4))
  end subroutine
  subroutine set_sin_port(buf, port)
    character(len=1), intent(inout) :: buf(*)
    integer(c_int), intent(in) :: port
    buf(5:8) = transfer(port, buf(5:8))
  end subroutine
  subroutine set_sin_addr(buf, addr)
    character(len=1), intent(inout) :: buf(*)
    integer(c_int), intent(in) :: addr
    buf(9:12) = transfer(addr, buf(9:12))
  end subroutine
end program server
program client
  use, intrinsic :: iso_c_binding
  implicit none
  integer(c_int), parameter :: AF_INET = 2, SOCK_STREAM = 1
  integer(c_int), parameter :: PORT = 12345
  integer(c_int) :: sock, n
  type(c_ptr) :: addr_ptr
  character(len=1), target :: addr_buf(16 + 2*4)
  character(len=1024) :: msg = "Hello from Fortran client!" // c_null_char
  interface
    function socket(domain, type, protocol) bind(c, name="socket")
      import c_int
      integer(c_int), value :: domain, type, protocol
      integer(c_int) :: socket
    end function socket
    function connect(sockfd, addr, addrlen) bind(c, name="connect")
      import c_int, c_ptr, c_socklen_t
      integer(c_int), value :: sockfd
      type(c_ptr), value :: addr
      integer(c_socklen_t), value :: addrlen
      integer(c_int) :: connect
    end function connect
    function send(sockfd, buf, len, flags) bind(c, name="send")
      import c_int, c_void, c_socklen_t
      integer(c_int), value :: sockfd
      type(c_ptr), value :: buf
      integer(c_socklen_t), value :: len
      integer(c_int), value :: flags
      integer(c_int) :: send
    end function send
    function close(fd) bind(c, name="close")
      import c_int
      integer(c_int), value :: fd
      integer(c_int) :: close
    end function close
  end interface

  ! 创建套接字
  sock = socket(AF_INET, SOCK_STREAM, 0_c_int)
  if (sock < 0) stop 'socket failed'

  ! 准备地址(127.0.0.1)
  addr_buf = 0
  call set_sin_family(addr_buf, AF_INET)
  call set_sin_port  (addr_buf, htons(PORT))
  call set_sin_addr  (addr_buf, inet_addr("127.0.0.1"))

  addr_ptr = c_loc(addr_buf)
  if (connect(sock, addr_ptr, 16 + 2*4_c_socklen_t) < 0) stop 'connect failed'

  n = send(sock, c_loc(msg), int(len_trim(msg), c_socklen_t), 0_c_int)
  if (n < 0) print *, 'send failed'

  call close(sock)
contains
  subroutine set_sin_family(buf, fam)
    character(len=1), intent(inout) :: buf(*)
    integer(c_int), value :: fam
    buf(1:4) = transfer(fam, buf(1:4))
  end subroutine
  subroutine set_sin_port(buf, port)
    character(len=1), intent(inout) :: buf(*)
    integer(c_int), value :: port
    buf(5:8) = transfer(port, buf(5:8))
  end subroutine
  subroutine set_sin_addr(buf, addr)
    character(len=1), intent(inout) :: buf(*)
    integer(c_int), value :: addr
    buf(9:12) = transfer(addr, buf(9:12))
  end subroutine
end program client

三、方式二 使用 libcurl 发起 HTTP 请求

program http_get
  use, intrinsic :: iso_c_binding
  implicit none
  interface
    function curl_easy_init() bind(c, name="curl_easy_init")
      import c_ptr
      type(c_ptr) :: curl_easy_init
    end function curl_easy_init
    function curl_easy_setopt(curl, opt, param) bind(c, name="curl_easy_setopt")
      import c_ptr, c_int
      type(c_ptr), value :: curl
      integer(c_int), value :: opt
      type(c_ptr), value :: param
      integer(c_int) :: curl_easy_setopt
    end function curl_easy_setopt
    function curl_easy_perform(curl) bind(c, name="curl_easy_perform")
      import c_ptr, c_int
      type(c_ptr), value :: curl
      integer(c_int) :: curl_easy_perform
    end function curl_easy_perform
    subroutine curl_easy_cleanup(curl) bind(c, name="curl_easy_cleanup")
      import c_ptr
      type(c_ptr), value :: curl
    end subroutine curl_easy_cleanup
    function curl_easy_strerror(code) bind(c, name="curl_easy_strerror")
      import c_ptr, c_int
      integer(c_int), value :: code
      type(c_ptr) :: curl_easy_strerror
    end interface

  type(c_ptr) :: curl
  integer(c_int) :: res
  character(len=:), allocatable :: url
  character(len=256) :: errbuf

  curl = curl_easy_init()
  if (.not. c_associated(curl)) then
    print *, "curl_easy_init failed"
    stop 1
  end if

  url = "http://example.com" // c_null_char
  call curl_easy_setopt(curl, 10002_c_int, c_loc(url))        ! CURLOPT_URL
  call curl_easy_setopt(curl, 52_c_int,  1_c_int)           ! CURLOPT_FOLLOWLOCATION
  call curl_easy_setopt(curl, 199_c_int, c_loc(errbuf))      ! CURLOPT_ERRORBUFFER

  res = curl_easy_perform(curl)
  if (res /= 0) then
    print '("curl_easy_perform failed: ", A)', trim(errbuf)
  end if

  call curl_easy_cleanup(curl)
end program http_get

四、编译链接与运行要点

五、常见坑与优化建议

0
看了该问题的人还看了