【问题标题】:Use socket with windows使用带窗户的插座
【发布时间】:2015-12-04 05:58:30
【问题描述】:

我目前正在使用 go 开发一个服务器/客户端项目,我需要在没有 net 包的情况下使用套接字。所以我使用我在 syscall 包上创建的 POSIX 函数。我的服务器程序在 Linux 上,我的客户端在 Windows (8) 上。

所以基本上,我想将客户端连接到服务器。问题是当客户端想要写入套接字时,它会显示“致命错误:windows 不支持”。

客户:

    package main

import (
    "fmt"
    "os"
    "runtime"
    s "syscall"
)

const (
    MAXSIZE = 500
    PORT    = 3000
)

var (
    ADDR = [4]byte{10, 8, 0, 1}
)

func Dial() (s.Handle, s.SockaddrInet4, error) {
    var sa s.SockaddrInet4 = s.SockaddrInet4{Port: PORT, Addr: ADDR}
    var d s.WSAData
    var sd s.Handle

    // a previous error told me to this
    if runtime.GOOS == "windows" {
        err := s.WSAStartup(uint32(0x202), &d)
        if err != nil {
            return sd, sa, err
        }
    }

    sd, err := s.Socket(s.AF_INET, s.SOCK_STREAM, 0)
    if err != nil {
        return sd, sa, err
    }

    s.Connect(sd, &sa)
    return sd, sa, err
}

func main() {
    sd, sa, err := Dial()
    check(err)
    defer s.Close(sd)

    _, err = s.Write(sd, make([]byte, 500,42))
    check(err)
}

func check(err error) {
    if err != nil {
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
        os.Exit(1)
    }
}

服务器(运行良好):

    package main

import (
    "fmt"
    "io/ioutil"
    "os"
    s "syscall"
)

const (
    PORT = 3000
)

func main() {
    var sa s.SockaddrInet4
    fmt.Println(sa)
    fd, err := s.Socket(s.AF_INET, s.SOCK_STREAM, 0)
    if err != nil {
        check(err)
    }
    defer s.Close(fd)
    if err := s.Bind(fd, &s.SockaddrInet4{Port: PORT, Addr: [4]byte{0, 0, 0, 0}}); err != nil {
        check(err)
    }

    if err := s.Listen(fd, 5); err != nil {
        check(err)
    }

    for {
        nfd, sa, err := s.Accept(fd)
        if err != nil {
            check(err)
        }

        go func(nfd int, sa s.Sockaddr) {
            var n int

            fmt.Println(sa)
            defer s.Close(nfd)

            b := make([]byte, 500)
            n, err = s.Read(nfd, b)
            check(err)
            fmt.Println(n)

        }(nfd, sa)
    }
}

func check(err error) {
    if err != nil {
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
        os.Exit(1)
    }
}

(对不起,如果我的英语不好,我是法国人)

【问题讨论】:

  • 你为什么要绕过net 包?这使您的程序不可移植,因为 windows 和 linux 使用不同的系统调用来操作套接字。
  • 为了简单起见,我的老师想要它。 ://
  • 这远非简单,但也许是一种学习体验。阅读 net 包中的 windows 特定代码,它已经为你完成了(提示,windows 不使用套接字上的write 系统调用)
  • 是的,正如您所说,这是一次学习经历。目的是使用 POSIX 库。
  • 除了windows socket api 肯定不是posix。

标签: windows sockets go posix


【解决方案1】:

就像 JimB 提到的,在 Windows 上,WSASend 用于通过网络发送数据。

因此,基本上,您必须对客户端代码进行更改的是:

 _, err = s.Write(sd, make([]byte, 500,42))

到:

data := make([]byte, 4)
buf := &s.WSABuf{
    Len: uint32(len(data)),
    Buf: &data[0],
}
var sent *uint32
overlapped := s.Overlapped{}
croutine := byte(0)

err = s.WSASendto(sd, buf, 1, sent, uint32(0), &sa, &overlapped, &croutine)
check(err)

【讨论】:

  • 非常感谢@Abelardo,我只需要修正 Len 的类型:Len: uint32(len(data), 并且效果很好! :)
  • 没问题@kindermoumoute :) 。如果其他人需要它,我会在我的回答中更改它。
  • 你有什么想法吗:link
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-31
  • 1970-01-01
  • 2012-02-23
  • 1970-01-01
  • 2016-10-28
  • 2017-11-12
相关资源
最近更新 更多