dongqu7778
2015-12-03 18:03
浏览 91
已采纳

在Windows上使用套接字

I'm currently working on a server/client project with go where I need to work with sockets without the net package. So I use POSIX functions I founded on syscall package. My server program in on Linux and my client in on Windows (8).

So basically, I want to connect the client to the server. The problem is when the client wants to Write in the socket it says "Fatal error : not supported by windows".

Client :

    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)
    }
}

Server (works well) :

    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)
    }
}

(Sry if my english is bad, I'm French)

  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • dsbruqxgt820011351 2015-12-03 20:50
    已采纳

    Like JimB mentioned, on Windows WSASend is used to send data over the network.

    So basically, what you have to change on your client code is:

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

    to:

    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)
    
    已采纳该答案
    打赏 评论

相关推荐 更多相似问题