I am trying to make a simple lua socket client for the Socket Server example, from the Lua Socket page.
The server part works though, I tried it with telnet.
But the client part isn't working.
local host, port = "127.0.0.1", 100
local socket = require("socket")
local tcp = assert(socket.tcp())
tcp:connect(host, port);
tcp:send("hello world");
It is only supposed to connect to it, send some data and receive some in return.
Can someone help me fix it?
Your server is likely receiving per line. As noted in the receive docs, this is the default receiving pattern. Try adding a newline to your client message. This completes the receive on the server:
local host, port = "127.0.0.1", 100
local socket = require("socket")
local tcp = assert(socket.tcp())
tcp:connect(host, port);
--note the newline below
tcp:send("hello world\n");
while true do
local s, status, partial = tcp:receive()
print(s or partial)
if status == "closed" then break end
end
tcp:close()
Related
Server:
s = TCPServer.open(6000)
loop do
Thread.start(s.accept) do |client|
# Keep receive and handle message from client
...
end
end
Clients:
server = TCPSocket.open(server_ip, 6000)
... # Send message if event, will keep TCP connection
Question:
Sometimes network down or client crash, How does sever know the TCP connection is alive? Is there a method or command the verify the connection?
Thanks
The most reliable way to verify the state of a TCP connection is to send an empty packet to the server and check if you get a response or an error. That will give you the current connection state of the socket.
I am learning TCPSocket and have a simple server written:
require 'socket'
server = TCPServer.open(2000)
loop {
client = server.accept
p client.gets
client.print("bar")
client.close
}
and simple client written:
require 'socket'
hostname = 'localhost'
port = 2000
socket = TCPSocket.open(hostname, port)
socket.print("foo")
p socket.gets
When I run these in separate terminals with either the server or client communicating one way (i.e. one "prints" and the other "gets") I get the expected string on the other side. When I run these as written, with the client first "print"-ing a message to the server and then the server "gets"ing it to then "print" a string to the client, it just hangs. What is causing this issue?
Your program does following:
The connection is established between client and server.
Client side
Calls print("foo") - exactly 3 bytes are transmitted to the server.
Calls gets - waits for data from server but server never send any.
Server side
Calls gets - The ruby function gets parse stream data and it always return the whole line. But the server received only "foo" and the it has no idea whether it is whole line or not. So it is waiting forever for new line character which client never send.
I am having trouble to bind to a server address. I have a connection, to a server (using Savon XML Library). Now I just need to listen to that server and gather its HTTP packets that sends. The server each time sends:
http://200.34.12.168/Videos/1/frame/0
http://200.34.12.168/Videos/1/frame/1
http://200.34.12.168/Videos/1/frame/2
http://200.34.12.168/Videos/1/frame/3
http://200.34.12.168/Videos/1/frame/4
...
..
which are HTTP packets. I am trying to create a UDP server that listens to these. This is what I have so far:
s = UDPSocket.new
s.bind('200.34.12.168', 80)
5.times do
text, sender = s.recvfrom(16)
puts text
end
it fails at the bind function. How can I listen to a UDP connection with ruby?
The Error I get:
"`bind': Can't assign requested address - bind(2) (Errno::EADDRNOTAVAIL)"
Do you have a web browser running - it may already be bound to port 80..
I'm trying to implement TCP hole punching with windows socket using mingw toolchain. I think the process is right but the hole doesn't seems to take. I used this as reference.
A and B connect to the server S
S sends to A, B's router IP + the port it used to connect to S
S does the same for B
A start 2 threads:
One thread tries connecting to B's router with the info sent by S
The other thread is waiting for an incoming connection on the same port used to connect to its router when it connected to S
B does the same
I have no issue in the code I think since:
A and B does get each other ip and port to use
They are both listening on the port they used to connect to their router when they contacted the server
They are both connecting to the right ip and port but get timed out (code error 10060)
I am missing something ?
EDIT: With the help of process explorer, I see that one of the client managed to establish a connection to the peer. But the peer doesn't seems to consider the connection to be made.
Here is what I captured with Wireshark. For the sake of the example, the server S and the client A are on the same PC. The server S listens on a specific port (8060) redirected to that PC. B still tries to connect on the right IP because it sees that the public address of A sent by S is localhost and therefore uses the public IP of S instead. (I have replaced the public IPs by placeholders)
EDIT 2: I think the confusion is due to the fact that both incoming and outcoming connection request data are transfered on the same port. Which seems to mess up the connection state because we don't know which socket will get the data from the port. If I quote msdn:
The SO_REUSEADDR socket option allows a socket to forcibly bind to a
port in use by another socket. The second socket calls setsockopt with
the optname parameter set to SO_REUSEADDR and the optval parameter set
to a boolean value of TRUE before calling bind on the same port as the
original socket. Once the second socket has successfully bound, the
behavior for all sockets bound to that port is indeterminate.
But talking on the same port is required by the TCP Hole Punching technique to open up the holes !
A start 2 threads:
One thread tries connecting to B's router with the info sent by S
The other thread is waiting for an incoming connection on the same port used to connect to its router when it connected to S
You can't do this with two threads, since it's just one operation. Every TCP connection that is making an outbound connection is also waiting for an incoming connection. You simply call 'connect', and you are both sending outbound SYNs to make a connection and waiting for inbound SYNs to make a connection.
You may, however, need to close your connection to the server. Your platform likely doesn't permit you to make a TCP connection from a port when you already have an established connection from that same port. So just as you start TCP hole punching, close the connection to the server. Bind a new TCP socket to that same port, and call connect.
A simple solution to traverse into NAT routers is to make your traffic follow a protocol that your NAT already has an algorithm for forwarding, such as FTP.
Use Wireshark to check tcp connection request(3-way Handhsake process) is going properly.
Ensure your Listener thread is having select() to de-multiplex the descriptor.
sockPeerConect(socket used to connect Other peer) is FD_SET() in Listener Thread.
Ensure your are checking
int Listener Thread()
{
while(true)
{
FD_SET(sockPeerConn);
FD_SET(sockServerConn);
FD_SET(nConnectedSock );
if (FD_ISSET(sockPeerConect)
{
/// and calling accept() in side the
nConnectedSock = accept( ....);
}
if (FD_ISSET(sockServerConn)
{
/// receive data from Server
recv(sockServerConn );
}
if (FD_ISSET(nConnectedSock )
{
/// Receive data from Other Peer
recv(nConnectedSock );
}
}
}
5.Ensure you are simultaneously starting peer connection A to B and B to A.
6.Start your Listener Thread Prior to Connection to server and Peer and have Single Listener Thread for receiving Server and Client.
not every router supports tcp hole punching, please check out the following paper which explains in detail:
Peer-to-Peer Communication Across Network Address Translators
My windows system has the firewall enabled.
I would like to allow incoming connections on a particular port (say: 4546).
Is there a ruby library that can help me do this ?
Detail:
I have a sinatra application (webserver) running on port 4546. I needed to bring down the firewall in order for it to work.
I am looking for a way to not keep the port 4546 under the firewall list.
Yes, you can do that with this:
require 'socket' # Get sockets from stdlib
server = TCPServer.open(4546) # Socket to listen on port 4546
loop { # Servers run forever
client = server.accept # Wait for a client to connect
client.puts(Time.now.ctime) # Send the time to the client
client.puts "Closing the connection. Bye!"
client.close # Disconnect from the client
}