2015-12-03 53 views
2

我目前正在開發一個服務器/客戶端項目,我需要在沒有網絡套件的情況下使用套接字。所以我使用我在syscall包上創建的POSIX函數。我的服務器程序在Linux上,我的客戶端在Windows上(8)。使用帶有窗口的套接字

所以基本上,我想連接客戶端到服務器。問題是,當客戶端想要在套接字中寫入它說「致命錯誤:不支持窗口」。

客戶:

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

(Sry基因如果我的英語不好,我是法國人)

+0

爲什麼你想繞過'net'包?這使得你的程序不可移植,因爲windows和linux使用不同的系統調用來操作套接字。 – JimB

+0

爲了簡單起見,我的老師想要它。 :/ – kindermoumoute

+0

這遠非簡單,但也許是一種學習體驗。閱讀網絡包中的窗口特定代碼,它已經在那裏完成了(提示,windows不使用套接字上的'write'系統調用) – JimB

回答

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) 
+0

非常感謝你@Abelardo,我只需要修復Len的類型:'Len:uint32(len(data),'它的功能完美!:) – kindermoumoute

+0

沒問題@kindermoumoute :)。將改變我的答案,以防其他人需要它。 –

+0

你有一個想法:[鏈接](http://stackoverflow.com/questions/34803056/wsarecv-doesnt-stop-reading)? – kindermoumoute