2012-03-13 32 views
9

Vì vậy, tôi đang làm cho một máy chủ cho thang máy của tôi trong Go, và tôi đang chạy hàm "handler" như một goroutine với một kết nối TCP. Tôi muốn nó đọc từ một kết nối, và nếu không có tín hiệu được phát hiện trong một khoảng thời gian nhất định tôi muốn nó trả về lỗi.Làm thế nào tôi có thể thực hiện net.Đọc đầu vào trong golang?

func handler(conn net.Conn){ 
    conn.SetReadTimeout(5e9) 
    for{ 
     data := make([]byte, 512) 
     _,err := conn.Read(data) 
    } 
} 

Chừng nào tôi còn có một khách hàng gửi những thứ qua kết nối nó có vẻ là làm việc tốt, nhưng ngay sau khi khách hàng ngừng gửi các chức năng net.Read trả về EOF lỗi và bắt đầu vòng lặp không có chậm trễ nào .

Điều này có thể là cách Đọc được cho là hoạt động, nhưng ai đó có thể đề xuất cách khác để xử lý sự cố mà không phải đóng và mở kết nối mỗi lần tôi muốn đọc gì đó?

+2

conn.SetReadTimeout (5e9) không phải là những gì bạn muốn. SetReadTimeout dự kiến ​​thời gian tuyệt đối, không phải là thời lượng. Hãy thử chỉ định là "time.Seconds * 10" và trình biên dịch sẽ khiếu nại. Những gì bạn đang nói ở trên là bạn muốn kết nối với thời gian ra tại 5000 giây sau ngày 1 tháng 1 năm 1970. Vì vậy, nó sẽ không chờ đợi ở tất cả. Thay vào đó bạn muốn một cái gì đó để có hiệu lực của conn.SetReadTimeout (time.Now(). Add (time.Seconds * 10)) cho thời gian chờ mười giây. – Crunge

Trả lời

19

Đọc đang hoạt động như mong đợi. Có vẻ như bạn muốn net.Đọc hoạt động như một kênh trong Go. Điều này là khá dễ dàng trong đi chỉ quấn net.Read trong một goroutine chạy và sử dụng lựa chọn để đọc từ kênh một goroutine thực sự rẻ và như vậy là một kênh

Ví dụ:

ch := make(chan []byte) 
eCh := make(chan error) 

// Start a goroutine to read from our net connection 
go func(ch chan []byte, eCh chan error) { 
    for { 
    // try to read the data 
    data := make([]byte, 512) 
    _,err := conn.Read(data) 
    if err != nil { 
     // send an error if it's encountered 
     eCh<- err 
     return 
    } 
    // send data if we read some. 
    ch<- data 
    } 
}(ch, eCh) 

ticker := time.Tick(time.Second) 
// continuously read from the connection 
for { 
    select { 
    // This case means we recieved data on the connection 
    case data := <-ch: 
     // Do something with the data 
    // This case means we got an error and the goroutine has finished 
    case err := <-eCh: 
     // handle our error then exit for loop 
     break; 
    // This will timeout on the read. 
    case <-ticker: 
     // do nothing? this is just so we can time out if we need to. 
     // you probably don't even need to have this here unless you want 
     // do something specifically on the timeout. 
    } 
} 
+2

Tài liệu hướng dẫn rõ ràng chống lại việc sử dụng ['time.Tick'] (https://golang.org/pkg/time/#Tick) theo cách này. –

+0

@DaveC: Tôi đã cập nhật mã để sử dụng một mã đơn lẻ. – nfirvine

+0

Ngoài ra, tôi muốn nói một giá trị nhỏ hơn nhiều so với giây sẽ thích hợp hơn. – nfirvine

0

Có thể bộ thu gom rác (GC) đóng một đầu của kết nối vì net.Conn trở thành đối tượng không thể truy cập từ quan điểm GC. Để ngăn chặn điều này: sau khi khách hàng ngừng gửi, hãy đảm bảo rằng kết nối máy khách được lưu trữ trong một biến có thể truy cập được bằng mã của bạn.

Một tùy chọn khác là ở đâu đó trong chương trình của bạn, bạn đang đóng một đầu kết nối mà không biết về nó.

+0

Tôi đã bỏ phiếu cho rằng bạn đã sai, nhưng tôi nghĩ bạn có thể đúng. SO không cho phép tôi tiết lộ ATM. – nfirvine

Các vấn đề liên quan