Lua Server Client Chat Example - server

I am trying to create a simple chat application with lua following are my files
-- load namespace
local socket = require("socket")
-- create a TCP socket and bind it to the local host, at any port
local server = assert(socket.bind("*", 0))
-- find out which port the OS chose for us
local ip, port = server:getsockname()
-- print a message informing what's up
print("Please telnet to localhost on port " .. port)
print("After connecting, you have 10s to enter a line to be echoed")
-- loop forever waiting for clients
local client = server:accept()
client:setoption("keepalive", true)
while 1 do
local line, err = client:receive()
print(line .. 'sent by client')
if not err then
client:send(line .. "\n")
else
print('error')
print(err)
end
end
client:close()
server.lua
local host, port = "127.0.0.1",arg[1]
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)
print("enter message to send")
local message = io.read()
print("sending message" .. message)
tcp:send(message);
if status == "closed" then break end
end
tcp:close()
client.lua
Now I cannot get my head around that the server does not receive after the first hello world and how do i connect another client while the server is already connected to the client, does lua offer any callback for receive or connection established?

You never send any actual end of line to the server, after the first line. Since message will not contain any line end, client:receive() will wait for the end forever (because it reads a line from the socket).
You can try calling server:accept() multiple times to wait for a new client. Combined with a timeout and coroutines, you can serve multiple clients.

Related

Unable to establish connection to a tcp socket server on aws ec2

I am trying to run a socket server on an aws ec2 ubuntu instance and then connecting with it using my local machine. I was successful with sending HTTP GET requests to my server hosted on aws ec2 instance and getting a response, but I am unable to connect the server and client using sockets, even after enabling custom TCP on the complete range of ports on the instance.
Here is a screenshot describing my instance's inbound and outbound rules :
screenshot
I used this python code from the internet to test socket networking :
socket_client.py :
import socket
def client_program():
host = "<aws instance public ip address>"
port = 8080 # socket server port number
client_socket = socket.socket() # instantiate
client_socket.connect((host, port)) # connect to the server
message = input(" -> ") # take input
while message.lower().strip() != 'bye':
client_socket.send(message.encode()) # send message
data = client_socket.recv(1024).decode() # receive response
print('Received from server: ' + data) # show in terminal
message = input(" -> ") # again take input
client_socket.close() # close the connection
if __name__ == '__main__':
client_program()
socket_server.py :
import socket
def server_program():
host = "0.0.0.0"
port = 8080 # initiate port no above 1024
server_socket = socket.socket() # get instance
# look closely. The bind() function takes tuple as argument
server_socket.bind((host, port)) # bind host address and port together
# configure how many client the server can listen simultaneously
server_socket.listen(2)
conn, address = server_socket.accept() # accept new connection
print("Connection from: " + str(address))
while True:
# receive data stream. it won't accept data packet greater than 1024 bytes
data = conn.recv(1024).decode()
if not data:
# if data is not received break
break
print("from connected user: " + str(data))
data = input(' -> ')
conn.send(data.encode()) # send data to the client
conn.close() # close the connection
if __name__ == '__main__':
server_program()
Note that the socket server-client are working completely fine when run on my local machine.
Please help if you know about how to fix this .
Edit - I have also tried with disabling firewall on the linux ec2 instance, but the problem still persists.
Thanks.

Having trouble using "sendto" in the lua sockets library

So I am trying to get a peer2peer matchmaking server going and I am having troubles with "sendto". I had some success with using "send" but then I couldn't do the hole punching step when the time came because it wouldn't switch peers to the other client for some reason. So now I am trying "sendto" but sendto cannot even send a message to the server.
Here is my code:
CLIENT:
local socket = require("socket")
local udp = socket.udp()
udp:setsockname("*", 0)
udp:settimeout(0)
--For server_ip I have also tried "localhost", "192.168.1.3", "127.0.0.1", and "127.0.0.0"
--none of them work. :(
local server_ip, server_port = "24.159.10.150", 30672
udp:sendto("FOO", server_ip, server_port)`
SERVER:
local socket = require("socket")
local udp = socket.udp()
udp:setsockname('*', 30672)
udp:settimeout(0)
while true do
local data, ip, port = udp:receivefrom()
if data ~= nil then
break;
end
end
print("SUCCESS!!")

Trouble with Lua TCP server when using loop to receive and send messages multiple times

I need a client and server to communicate through a socket. The client tells the server that it wants a specific message (through a string "arquivo") and gets the message that is supposed to be 10KB long. Both of them have to maintain the connection open in case the client wants to ask for the message again with that same string. I could implement that for 1 exchange, closing the connection. When I put in a while though, the server apparently sends the message but it never gets to the client, unless I close the terminal window where the client is running. I ran each in a separate terminal window and tested the client's code with a server that only transmits the message once and then closes the connection and the message came through. The problematic server code is as follows:
filename = "file10KB.txt"
file = assert(io.open(filename, "r"))
msg = file:read("*a")
file:close()
socket = require("socket")
host = "*"
port = 8080
print("Binding to host '" .. host .. "' and port " .. port .. "...")
server = assert(socket.bind(host, port))
server:setoption("reuseaddr", true)
ipaddress, socketport = server:getsockname()
assert(ipaddress, socketport)
print("Waiting connection from client on " .. ipaddress .. ":" .. socketport .. "...")
connection = assert(server:accept())
connection:setoption("keepalive", true)
connection:settimeout(10)
print("Connected!")
while true do
print("Waiting for request...")
data, errormsg = connection:receive()
if data == "arquivo" then
print("Proper request received, sending message...")
assert(connection:send(msg .. "\n"))
print("Message sent!")
elseif not errormsg then
print("Invalid request.")
break
else
print("Error message: " .. errormsg)
break
end
end
Also, my client's code:
socket = require("socket")
host = "localhost"
port = 8080
print("Attempting connection to server '" .. host .. "' and port " .. port .. "...")
client = assert(socket.connect(host, port))
client:setoption("keepalive", true)
client:setoption("reuseaddr", true)
client:settimeout(10)
print("Connected!")
repeat
print("Sending message request...")
assert(client:send("arquivo" .. "\n"))
print("Message request sent! Waiting for message...")
data, errormsg = client:receive("*a")
if data then
print("Message received!")
print(data)
else
print("Failed to receive message.")
break
end
until not client
I'm new to Lua and to sockets and I followed some tutorials I found on the web, such as http://www.portugal-a-programar.pt/topic/36175-aprendendo-a-usar-lua-socket/ (it's in portuguese). I just hope any of you could shed a light on what I'm missing. I'm using Mac OS X machine by the way, don't know if that's any helpful.
When I put in a while though, the server apparently sends the message but it never gets to the client, unless I close the terminal window where the client is running
I don't know what this means. Closing the terminal window should close the client, which hardly means it will suddenly receive a message.
However there are numerous problems with this, too long for comments:
You need to set SO_REUSEADDR before binding. Afterwards is too late.
You don't need to set it at the client at all, but if you do it must be before connecting.
The sockname check in the server is pointless. It can't fail.
Your server only accepts one connection.
Your server never closes the connection.
Your server doesn't appear to recognized end of stream correctly.
Your client never closes the connection.
The problem was in the
data, errormsg = client:receive("*a")
line in the client's code. The option *a only receives when the connection is closed and changing it to *l or nothing like below made it work.
data, errormsg = client:receive()

How to close() server connection with key-press? (Simple networking with Socket)

So I am very new to networking and the Socket module in Python. So I watched some Youtube tutorials and found one on how to write the code for a simple server. My problem is right when the server receives data from the client, the server close() and loses connection to the client right when it receives the data. I want the server to automatically lose connection to the client but not "shutdown" or close(). I want to set it (if its possible) so that while the server is running in my Python Shell, if I want to close() the connection I use hot keys like for example "Control+E"? Here is my code so far:
#!/usr/bin/python
import socket
import sys
# Create a TCP/IP socket to listen on
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Prevent from "adress already in use" upon server restart
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Bind the socket to port 8081 on all interfaces
server_address = ('localhost',8081)
print ('starting up on %s port %s')%(server_address)
server.bind(server_address)
#Listen for connections
server.listen(5)
#Wait for one incoming connection
connection, client_address = server.accept()
print 'connection from', connection.getpeername()
# Let's recieve something
data = connection.recv(4096)
if data:
print "Recived ", repr(data)
#send the data back nicely formatted
data = data.rstrip()
connection.send("%s\n%s\n%s\n"%('-'*80, data.center(80),'-'*80))
# lose the connection from our side (the Server side)
connection.shutdown(socket.SHUT_RD | socket.SHUT_WR)
connection.close()
print 'Connection closed'
# And stop listening
server.close()
==================================================================================
Here is the code I am using (on the server side):
#!/usr/bin/python
import socket, sys
import select
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#Let's set the socket option reuse to 1, so that our server terminates quicker
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("localhost", 8081))
srv.listen(5)
while True:
print "Waiting for a client to connect"
(client, c_address) = srv.accept() #blocking wait for client
print "Client connected"
# Client has connected, add him to a list which we can poll for data
client_list = [client]
while close_socket_condition == 0:
ready_to_read, ready_to_write, in_error = select.select(client_list, [], [] , 1) #timeout 1 second
for s in ready_to_read: #Check if there is any socket that has data ready for us
data = client.recv(1024) # blocks until some data is read
if data:
client.send("echo:" + data)
client.close()
close_socket_condition = 1
And here is the error it is giving me when I try to send a string to the server:
data = s.recv(1024)
File "C:\Python27\lib\socket.py", line 170, in _dummy
raise error(EBADF, 'Bad file descriptor')
error: [Errno 9] Bad file descriptor
Here is example on a non-blocking socket read with similar structure as yours.
The server will establish a socket in localhost, and wait for a client to connect. After that it will start polling the socket for data, and also keep checking the exit condition close_socket_condition. Handling ctrl-e or other exit events will be left as an exercise :)
First we start socket, very much the same way as you:
#!/usr/bin/python
import socket, sys
import select
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#Let's set the socket option reuse to 1, so that our server terminates quicker
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("localhost", 8081))
srv.listen(5)
Then we declare our external exit condition close_socket_condition, and start eternal while loop that will always welcome new clients:
close_socket_condition = 0
while True:
print "Waiting for a client to connect"
(client, c_address) = srv.accept() #blocking wait for client
print "Client connected"
Now a client has connected, and we should start our service loop:
# Client has connected, add him to a list which we can poll for data
client_list = [client]
while close_socket_condition == 0:
Inside the service loop we will keep polling his socket for data and if nothing has arrived, we check for exit condition:
ready_to_read, ready_to_write, in_error = select.select(client_list, [], [] , 1) #timeout 1 second
for s in ready_to_read: #Check if there is any socket that has data ready for us
data = client.recv(1024) # blocks until some data is read
if data:
client.send("echo:" + data)
client.close()
close_socket_condition = 1
This code is simplified example, but the server will keep accepting new clients, and always reuse the connection. It does not handle client side terminations etc.
Hope it helps

Recover a TCP connection

I have a simple Python server which can handle multiple clients:
import select
import socket
import sys
host = ''
port = 50000
backlog = 5
size = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(backlog)
input = [server,sys.stdin]
running = 1
while running:
inputready,outputready,exceptready = select.select(input,[],[])
for s in inputready:
if s == server:
# handle the server socket
client, address = server.accept()
input.append(client)
elif s == sys.stdin:
# handle standard input
junk = sys.stdin.readline()
running = 0
else:
# handle all other sockets
data = s.recv(size)
if data:
s.send(data)
else:
s.close()
input.remove(s)
server.close()
One client connects to it and they can communicate. I have a third box from where I am sending a RST signal to the server (using Scapy). The TCP state diagram does not say if an endpoint is supposed to try to recover a connection when it sees a RESET. Is there any way I can force the server to recover the connection? (I want it to send back a SYN so that it gets connected to the third client)
Your question doesn't make much sense. TCP just doesn't work like that.
Re "The TCP state diagram does not say if an endpoint is supposed to try to recover a connection when it sees a RESET": RFC 793 #3.4 explicitly says "If the receiver was in any other state [than LISTEN or SYN-RECEIVED], it aborts the connection and advises the user and goes to the CLOSED state.".
An RST won't disturb a connection unless it arrives over that connection. I guess you could plausibly forge one, but you would have to know the current TCP sequence number, and you can't get that from within either of the peers, let alone a third host.
If you succeeded somehow, the connection would then be dead, finished, kaput. Can't see the point of that either.
I can't attach any meaning to your requirement for the server to send a SYN to the third host, in response to an RST from the third host, that has been made to appear as though it came from the second host. TCP just doesn't work anything like this either.
If you want the server to connect to the third host it will just have to call connect() like everybody else. In which case it becomes a client, of course.