英文:
Use socket with windows
问题
我目前正在使用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
// 之前的错误提示我这样做
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, "致命错误:%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, "致命错误:%s", err.Error())
os.Exit(1)
}
}
希望对你有帮助!
英文:
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
得分: 2
像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)
英文:
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论