How can I get HTTP RPC Server and client to work? - go

I am trying to send messages from client to server and back using the exact HTTP RPC server/client code given here.
However, when I run the server, my command line becomes blank because the server starts listening using:
err := http.ListenAndServe(":1234", nil)
if err != nil {
fmt.Println(err.Error())
}
In the client code, I need to get an argument from the command line for client to run:
serverAddress := os.Args[1]
However, this argument is not available because the server code makes my command line blank.
How can I get the server and client to work on the same command line window?

Related

Can't upload file via FTP on Golang

I'm currently using github.com/jlaffaye/ftp on Go to send files.
I'm trying to connect to an FTP and upload a zipped file of about 700MB.
I connect to server properly and change the working dir but when I'm about to call the Stor function, it responds with "connection refused" and drops.
This is the code:
ftpFile="hola.txt"
fileOpen, err := os.Open(ftpFile) // For read access.
if err != nil {
fmt.Println("error "+ftpFile)
panic(err)
} else {
fmt.Println("abierto "+ftpFile)
}
reader:=bufio.NewReader(fileOpen)
err = client.Stor(ftpDir+ftpFile,reader)
if err != nil {
fmt.Println("error en stor "+ftpDir+ftpFile)
panic(err)
} else {
fmt.Println("subiendo "+ftpFile)
}
defer fileOpen.Close()
I'm opening a file with os.Open then read it with bufio.NewReader and pass it to the Stor function but it disconnects. The FTP is good as I was connected to it via FileZilla, the zipfile or txt file (in this code example) are both good and I believe I'm missing the shot when it comes to the bufio.NewReader but I can't find a working example of reading a file and using this goftp library.
Update:
Here's the logfile
220 Microsoft FTP Service
USER *user goes here*
331 Password required
PASS *plain text password goes here*
230 User logged in.
FEAT
211-Extended features supported:
LANG EN*
UTF8
AUTH TLS;TLS-C;SSL;TLS-P;
PBSZ
PROT C;P;
CCC
HOST
SIZE
MDTM
REST STREAM
211 END
TYPE I
200 Type set to I.
OPTS UTF8 ON
200 OPTS UTF8 command successful - UTF8 encoding now ON.
CWD /web-import/pre/
250 CWD command successful.
PWD
257 "/web-import/pre" is current directory.
PASV
227 Entering Passive Mode (x,x,x,x,x,x).
Update: Looks like someone had the same problem some weeks ago: goftp - 229 Entering Extended Passive Mode now I'll be looking for solutions and will post here.
Update: Changed the script to connect to a CentOS server and got the same error. Now that the FTP server is discarded then there are 2 culprits: goftp package and the script itself.
Update: Tried again with a simpler script following example at documentation and failed again at the same spot. Had to report issue on developer's Github https://github.com/jlaffaye/ftp/issues/272
Update: I connected via terminal and opened FTP from command line. I typed "ls" by mistake and got this error
227 Entering Passive Mode (x,x,x,x,x,x).
ftp: connect: Connection refused
Last Update: After coding and debugging in the end it wasn't the goftp package neither the server neither the client. It was my firewall that blocked my ftp from going PASV. I whitelisted the ip and it worked perfectly.

TCP Listener is not shut down completely

I have a TCP Listener that initialized as next:
myListener := net.Listen("tcp", addr)
Then am able to receive connections and process them. Then I need to close the server in order that I can reuse the same port but this is not happening, this is how am closing the tcp server:
myListener.Close()
In the client side am closing all the existent TCP connections to that server and then from the terminal I see that those connections are being close but the port is still in use by the server and listening (even when is not accepting new connections which is right according to documentation). This is how I check in the terminal:
netstat -an | grep 8080
And after close the client side connections I get this and cannot reuse the port:
tcp46 0 0 *.8080 *.* LISTEN
After doing myListener.Close() I waited some time but in the terminal the port is still in use.
In addition to checking the error from the net.Listener as stated in https://stackoverflow.com/a/65638937/1435495
You will also want to add a defer to your myListener.Close() will help ensure that the close does actually execute even if something would cause the app to exit prematurely.
defer myListener.Close()
The net.Listen function returns two parameters (Listener, error), in your example above you appear to only be capturing the Listener and not the error.
Assuming you're actually capturing it, you should check if the error is empty before you begin using the listener.
package main
import "net"
func main() {
myListener, err := net.Listen("tcp", ":8080")
if err != nil {
panic(err)
}
myListener.Close()
}
Something similar to the snippet above should work. Now if you're not getting an error (I presume you will get an error), the problem you likely have is that something else is already using that port.
Try running your netstat as root so you can see all processes which will give you a better idea of what is holding on to that port.
sudo netstat -apn | grep -i listen | grep 8080

Why does http.Get("http://[::]:1234") work?

I was writing a test where I wanted an HTTP server to listen on a random port and then connect to this port. I wrote:
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("foo")
})
listener, err := net.Listen("tcp", ":0")
fmt.Println(err)
httpServer := &http.Server{Handler: mux}
go httpServer.Serve(listener)
fmt.Println("http://" + listener.Addr().String())
r, err := http.Get("http://" + listener.Addr().String())
fmt.Println(r)
fmt.Println(err)
I meant to write net.Listen("tcp", "127.0.0.1:0") but accidentally wrote net.Listen("tcp", ":0").
For "http://" + listener.Addr().String() it prints:
http://[::]:1709
where as far as I understand the "bracket colon colon bracket" means "all interfaces".
To my surprise, the http.Get("http://[::]:1709") works, it connects to the webserver and "foo" is printed.
How is "http://[::]:1709" a valid address?
At least on a Linux system, this results in a connection being made to localhost.
The address :: is IN6ADDR_ANY, typically used when listening to listen for connections to any IPv6 address on the system. It's analogous to INADDR_ANY, also known as 0.0.0.0 in IPv4.
Occasionally someone attempts to use one of these addresses as the destination address for an outgoing connection. When this happens:
When making an outgoing connection to 0.0.0.0, Linux actually connects from 127.0.0.1 to 127.0.0.1.
Similarly, when making an outgoing connection to ::, Linux actually connects from ::1 to ::1. Here is an example, taken from one of my websites (which happens to be an IP address lookup tool):
[error#murloc ~]$ curl -k -H "Host: myip.addr.space" https://[::]:8443/
::1
For completeness, here is the IPv4 version:
[error#murloc ~]$ curl -k -H "Host: myip.addr.space" https://0.0.0.0:8443/
127.0.0.1
Note that this is OS-specific. You would have received an error on Windows.

golang exec incorrect behavior

I'm using following code segment to get the XML definition of a virtual machine running on XEN Hypervisor. The code is trying to execute the command virsh dumpxml Ubutnu14 which will give the XML of the VM named Ubuntu14
virshCmd := exec.Command("virsh", "dumpxml", "Ubuntu14")
var virshCmdOutput bytes.Buffer
var stderr bytes.Buffer
virshCmd.Stdout = &virshCmdOutput
virshCmd.Stderr = &stderr
err := virshCmd.Run()
if err != nil {
fmt.Println(err)
fmt.Println(stderr.String())
}
fmt.Println(virshCmdOutput.String())
This code always goes into the error condition for the given domain name and I get the following output.
exit status 1
error: failed to get domain 'Ubuntu14'
error: Domain not found: no domain with matching name 'Ubuntu14'
But if I run the standalone command virsh dumpxml Ubuntu14, I get the correct XML definition.
I would appreciate if someone could give me some hints on what I'm doing wrong. My host machine is Ubuntu-16.04 and golang version is go1.6.2 linux/amd64
I expect you are running virsh as a different user in these two scenarios, and since you don't provide any URI, it is connecting to a different libvirtd instance. If you run virsh as non-root, then it'll usually connect to qemu:///session, but if you run virsh as root, then it'll usually connect to qemu:///system. VMs registered against one URI, will not be visible when connecting to the other URI.
BTW, if you're using go, you'd be much better off using the native Go library bindings for libvirt instead of exec'ing virsh. Your "virsh dumpxml" invokation is pretty much equivalent to this:
import (
"github.com/libvirt/libvirt-go"
)
conn, err := libvirt.NewConnect("qemu:///system")
dom, err := conn.LookupDomainByName("Ubuntu14")
xml, err := dom.GetXMLDesc(0)
(obviously do error handling too)

exec.Command does not register error from Go's own pprof tool

Here is my code:
cmd := exec.Command("go", "tool", "pprof", "-dot", "-lines", "http://google.com")
out, err := cmd.Output()
if err != nil {
panic(err)
}
println(string(out))
When I run the exact same command in my console, I see:
$ go tool pprof -dot -lines http://google.com
Fetching profile from http://google.com/profilez
Please wait... (30s)
server response: 404 Not Found
However, my go program does not register that this is an error. Oddly, the variable out prints as an empty string and err is nil. What is going on?
To clarify, I am profiling http://google.com to purposefully create an error. I would normally profile a real Go application.
The text
Fetching profile from http://google.com/profilez
Please wait... (30s)
server response: 404 Not Found
is written to stderr. Your program captures stdout, which is empty. Consider calling:
out, err := cmd.CombinedOutput()
to grab both stdout and stderr.
cmd.Output() and cmd.CombinedOutput() return err == nil because the command exits with status zero. Perhaps an issue should be filed requesting that the command exit with non-zero status.

Resources