I am building a tcp socket server in golang. It works well with less than ~140 client connection. But if i try to set max connection number to 500, after 140th clients do not connect to the server.
I increased file descriptor count to 1048576 but it does not still work.
$ulimit -n
1048576
I think the problem comes from operation system.(server and clients work on same machine) So OS information:
Mac OS 10.12 Sierra 64 bit.
Does anyone have any idea why i can't increase tcp connection number?
github
I am on the same operating system as you, but I could not reproduce your issue. I am using Go version 1.7.4. I have not tested on Go 1.8, but it was released earlier today.
I created two files, server.go and client.go (reproduced below). When I run them, I get way more than 140 connections. Before running, I switched to root and setup the ulimit like so:
$ sudo -s
$ ulimit -n 10000
The client outputs:
Established 1 connections
...
Established 2971 connections
panic: dial tcp 127.0.0.1:1337: socket: too many open files in system
The server outputs something very similar.
Here is client.go:
package main
import (
"fmt"
"net"
)
func main() {
var numConns int
for {
_, err := net.Dial("tcp", "127.0.0.1:1337")
if err != nil {
panic(err)
}
numConns++
fmt.Println("Established", numConns, "connections")
}
}
And server.go:
package main
import (
"fmt"
"net"
)
func main() {
listener, err := net.Listen("tcp", ":1337")
if err != nil {
panic(err)
}
var numConns int
for {
_, err := listener.Accept()
if err != nil {
panic(err)
}
numConns++
fmt.Println("Got", numConns, "connections")
}
}
This is not a problem with the operating system, but the hardware. It is likely a problem with your router. Commercial routers do tend to fail when you get into that range. My guess is that Alex is testing at a large company or university where they have commercial grade routers, but you are testing at home.
Related
I am not able to manage the wireguard interface using wgctl on Windows (10). I have used it on linux and all is fine. I'm using Windows 10 latest updates, wireguard.exe latest, go 1.17.3 latest.
I am using a tunnel created with wireguard.exe /installtunnelservice /path/wg0.conf. If I manage the tunnel with the wireguard GUI, it all works fine. But I need to do it programatically.
C:\>wg
interface: wg0
public key: K0BZ3Bk...5tCWo=
private key: (hidden)
listening port: 57538
peer: 7W6tOXI...F7zAo=
endpoint: 159....105:51820
allowed ips: 100.127.128.0/18
latest handshake: 43 seconds ago
transfer: 31.61 KiB received, 115.69 KiB sent
persistent keepalive: every 25 seconds
...
The following code exits with "file does not exist". Having stepped the code into the library, I think that wireguard.exe is using NT Kernel mode and the library does not support it? Can someone please confirm? What is the best way around this?
package main
import (
"log"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
func main() {
wgc, err := wgctrl.New()
if err != nil {
log.Printf("wgctrl.New: %s", err)
}
defer wgc.Close()
cfg := wgtypes.Config{}
port := 51822
cfg.ListenPort = &port
err = wgc.ConfigureDevice("wg0", cfg)
if err != nil {
log.Printf("wgc.ConfigureDevice: %s", err)
}
}
After escalating the issue on GitHub, it turned out to be a bug in the library which was promptly fixed not long after I posted this.
I can not send multicast request to LAN from Go on Win10.
I have Windows 10 1909.
I am running wireshark with filter host 239.255.255.250 or host 172.19.21.116 or port 1982 where .116 is IP of device I am looking for.
I have YeeLight UWP app installed
I have this code (removed every if err != nil):
package main
import (
"bytes"
"net"
"time"
)
func main() {
bulbMulticastAddr := &net.UDPAddr{IP: net.IPv4(239, 255, 255, 250), Port: 1982}
bulbSearchRequest := new(bytes.Buffer)
_, err := bulbSearchRequest.WriteString("M-SEARCH * HTTP/1.1\r\nHOST:239.255.255.250:1982\r\nMAN:\"ssdp:discover\"\r\nST:wifi_bulb\r\n")
conn, err := net.ListenUDP("udp4", bulbMulticastAddr)
conn.WriteTo(bulbSearchRequest.Bytes(), bulbMulticastAddr)
time.Sleep(time.Duration(6) * time.Second)
}
When I run go run myapp, in WireShark I see single UDP packet with source 127.0.0.1 and destination 239.255.255.250
When I run Yeelight UWP app, in WireShark I see in WireShark two same packets: one using Ethernet interface and one using loopback.
And after some time OS works (few hours - different apps are running), it starts working.
When I use
iflist, _ := net.Interfaces() // iflist[0] is Ethernet
conn, err := net.ListenMulticastUDP("udp4", &iflist[0], bulbMulticastAddr)
conn.WriteTo(bulbSearchRequest.Bytes(), bulbMulticastAddr)
Everything goes right
What am I doing wrong? Each tutorial about multicast shows the way I am doing is right, but it does not work as expected. I am missing something?
Why ListenUDP() not working as expected?
go version go1.14 windows/amd64
single IP can only support 65535 port to single destination.
I hope the client can reuse the old tcp_session immediately during the performance test, even if session is still in time_wait status.
On my Linux machine, I had opened these switch
sysctl -w net.ipv4.tcp_timestamps=1
sysctl -w net.ipv4.tcp_tw_recycle=1
sysctl -w net.ipv4.tcp_tw_reuse=1
Then I write the following code to verify the socket_reuse option with golang.
In the code, I bind the local port 12345.
after run first
$go run 1.go
$netstat -nat | grep 12345
tcp 0 0 192.168.1.11:12345 111.161.3.173:80 TIME_WAIT
after run secondary
$go run 1.go
Client Connect() called error: cannot assign requested address
It seems that the SO_REUSEADDR can not work.
Can Anyone help to resolve this ?
package main
import (
"fmt"
. "syscall"
)
func main() {
var (
clientsock int
serveraddr SockaddrInet4
err error
)
if clientsock, err = Socket(AF_INET, SOCK_STREAM, IPPROTO_IP); err != nil {
fmt.Println("Client Socket() called error:", err.Error())
return
}
SetsockoptInt(clientsock, SOL_SOCKET, SO_REUSEADDR, 1)
defer Shutdown(clientsock, SHUT_RDWR)
serveraddr.Addr = [4]byte{111, 161, 3, 173}
serveraddr.Port = 80
err = Bind(clientsock, &SockaddrInet4{
Port: 12345,
})
if err = Connect(clientsock, &serveraddr); err != nil {
fmt.Println("Client Connect() called error:", err.Error())
return
}
}
You ought to add two changes to your code:
1) Set socket option unix.SO_REUSEPORT.
if errReusePort := SetsockoptInt(clientsock, SOL_SOCKET, unix.SO_REUSEPORT, 1); errReusePort != nil {
fmt.Printf("reuse port error: %v\n", errReusePort)
return
}
2) Make your code to connect to distinct remote TCP endpoints. Otherwise, due to single source addr/port, TCP wouldn't be able to distinguish between two identical connections (protocol, src-addr, src-port, dst-addr, dst-port). The example below specifies two remote server addresses in the command-line.
$ go run main.go 127.0.0.1
connected
$ go run main.go 127.0.0.2
connected
Find full working code on playground: https://play.golang.org/p/HYLkWlVH6T4
My binary takes a port parameter and starts a http server. If pass a 0 to the -port, it will find a free port and start on it.
After this, how do I find which port is this if I have the command object with me and can get the process id? I am trying to write my application in golang. I am also curious how this is done in general.
It's OS specific, but on linux you can do
netstat -npl
that will list which programs are listening on which ports
If you just want to print it out from your app, you can use the alternative form of starting the http server by creating your own tcp listener and then call http.Serve
example:
package main
import (
"fmt"
"net"
"net/http"
"os"
)
func main() {
lsnr, err := net.Listen("tcp", ":0")
if err != nil {
fmt.Println("Error listening:", err)
os.Exit(1)
}
fmt.Println("Listening on:", lsnr.Addr())
err = http.Serve(lsnr, nil)
fmt.Println("Server exited with:", err)
os.Exit(1)
}
outputs:
Listening on: [::]:53939
package main
import (
"fmt"
"net"
)
func main() {
var localaddr net.TCPAddr
var remoteaddr net.TCPAddr
localaddr.IP = net.ParseIP("192.168.1.104")
localaddr.Port = 6000
remoteaddr.IP = net.ParseIP("192.168.1.104")
remoteaddr.Port = 5000
if localaddr.IP == nil || remoteaddr.IP == nil {
fmt.Println("error")
}
if _, err := net.DialTCP("tcp", &localaddr, &remoteaddr); err != nil {
fmt.Println(err)
}
fmt.Println("End")
}
If the function specify local IP address, it always reports a run time error "dial tcp 192.168.1.104:5000: An invalid argument was supplied." I'm confused, should it always be a nil for local IP address ?
go version : 1.1 Beta
OS: Win7 64bit
Tried in go 1.0.3, it seemed OK
Go's net package, like most such implementations, recognizes port-only syntax for connecting to localhost:
:5000
is equivalent to
<my-ip-address>:5000
Thus, you can do:
net.Dial("tcp", ":5000")
No, it is ok to have laddr argument specified in DialTCP. The problem is that the specified port (6000) is outside of default Win7 dynamic port range and couldn't be used for outgoing connection. It works on Linux and Mac, actually (if you don't forget to change the IP address to one of your own system).