Simple Python Socket Server Not Taking Conditional Statement - python

I attempted to find an answer for this, but most examples out there are for purely echo base Socket Servers.
Basically I have the following code:
import socket
import sys
from thread import *
HOST = '' # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
#Bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error as msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
#Start listening on socket
s.listen(10)
print 'Socket now listening'
#Function for handling connections. This will be used to create threads
def clientthread(conn):
#Sending message to connected client
conn.send('Welcome to the server. Type something and hit enter\n') #send only takes string
#infinite loop so that function do not terminate and thread do not end.
while True:
#Receiving from client
data = conn.recv(1024)
if data == "hello":
reply = 'OK...Hello back to you'
else:
reply = '01:OK - ' + data
if not data:
break
conn.sendall(reply)
#came out of loop
conn.close()
#now keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
#start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.
start_new_thread(clientthread ,(conn,))
s.close()
Everything works great until I try to use a conditional statement. I am very new to python and I am using this as a way to learn it a little better, but when the following line runs it skips the if each time.
#Receiving from client
data = conn.recv(1024)
if data == "hello":
reply = 'Why hello there!'
else:
reply = '01:OK - ' + data
if not data:
break
conn.sendall(reply)
From the telnet client I am connecting to it just echos everything I send it including the 'hello' I send it rather than the phrase.
I have a feeling that it is something simple, but I am not sure the format of the data variable.

Very close!
Telnet will send whatever EOL delimiter you gave it, along with the text. So if you type "data" and press enter, data is actually something like hello\r\n.
You can effectively ignore this whitespace by doing something like changing
data = conn.recv(1024)
to
data = conn.recv(1024).strip()
And you should be good to go.
EDIT:
As noted in the comments, the network may split up the message into multiple packets. To work around this, you can use use the socket.makefile() method and get a file-like object and then use readline() which will block until a complete line is available. For example, changing clientthread to:
def clientthread(conn):
#Sending message to connected client
conn.send('Welcome to the server. Type something and hit enter\n') #send only takes string
sfh = conn.makefile("r+b", bufsize=0)
#infinite loop so that function do not terminate and thread do not end.
while True:
#Receiving from client
data = sfh.readline().strip()
if data == "hello":
reply = 'OK...Hello back to you'
else:
reply = '01:OK - ' + data
if not data:
break
conn.sendall(reply)
#came out of loop
conn.close()
== PYTHON ==
Socket created
Socket bind complete
Socket now listening
Connected with 192.168.1.10:42749
== TELNET ==
$ telnet 192.168.1.106 8888
Trying 192.168.1.106...
Connected to 192.168.1.106.
Escape character is '^]'.
Welcome to the server. Type something and hit enter
hello
OK...Hello back to you

Related

Why is socket.recv() sometimes blocking and sometimes not? [duplicate]

This question already has an answer here:
Python Bidirectional TCP Socket Hanging on socket.recv
(1 answer)
Closed 3 years ago.
I'm trying to make a client-server application in which:
the client sends a message (name of a function) to the server
the server receives the message, calls the corresponding function and returns the results to the client.
I'm able to do this only if the message from the client is one; if I want to call two or more functions, and therefore send two or more messages, I get some problems because I need to add a loop inside the server.
In particular, what is not clear to me is the socket function recv(). Usually, to receive data I write something like this (without setblocking()) and I never had any problems:
while True:
data = sock.recv(BUFFER)
results += data.decode()
if not data:
break
But if I add a while True: to the server (in order to wait for the other functions), then the client never exits from sock.rev(). Why? I expect that function to be always blocking or always non-blocking based on how it was set sock.setblocking().
I already tried with settimeout() and it worked, but performances are really important so I would like to avoid every possible delay.
Anyway, the main question is why recv() is behaving differently; then if you had any suggestions to solve my task it would be really appreciated.
Here's a simple simulation of the real application.
Client:
import socket
BUFFER = 1024
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address= ('localhost', 14000)
sock.connect(bridge_address)
msg1 = "function 1".encode()
msg2 = "function 2".encode()
results1 = " "
results2 = " "
sock.sendall(msg1)
while True:
data = sock.recv(BUFFER)
results1 += data.decode()
if not data:
print('no more data')
break
sock.sendall(msg2)
while True:
data = sock.recv(BUFFER)
results2 += data.decode()
if not data:
print('no more data')
break
sock.close()
print('Results 1: ',results1)
print('Results 2: ',results2)
Server:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 14000)
sock.bind(server_address)
sock.listen(1)
msg = ""
for i in range(4096):
msg += str(i) + " "
while True:
print('waiting for a connection')
client, client_address = sock.accept()
try:
while True:
data = client.recv(128)
if not data:
print('no more data from')
break
client.sendall(msg.encode())
finally:
print('connection closed.\n')
client.close()
You are explicitly forcing the server side socket to recieve the message from the client, even when the client is not sending anything.
data = client.recv(128)
if not data:
print('no more data from')
break
if case in the code snippet above will only execute when the client socket goes down.
One method to solve this would be to first send the size of the message and then call recv accordingly for the specified number of bytes.

Python - Socket Communication, multiple messages

I'm stuck on this socket communication, I've looked everywhere but I haven't found an answer yet.
THE PROBLEM: I can only send 1 message from the client before it either gives me an error or ends the script.
I need to be able to send multiple messages to the server.
The server side (shown below) should be fine:
# Echo server program
import socket
import time
import os
#-----------------------------------------------------------------------------------------------------------------------
today = time.strftime('%Y.%m.%d')
logFileName = "log - " + today + ".txt"
HOST = '10.0.0.16'
PORT = 8080 # Reserve a port for your service
BUFFER_SIZE = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Create a socket object
s.bind((HOST, PORT)) # Bind to the port
def print_write(text):
log.write(time.strftime("%H:%M:%S") + " | " + text)
log.write("\n")
print text
#-----------------------------------------------------------------------------------------------------------------------
if os.path.isfile(logFileName) is True:
log = open(logFileName, 'a+')
print_write("[SERVER] Log for " + today + " already exists.")
print_write("[SERVER] Starting comms")
else:
print "[SERVER] Log doesn't exist"
log = open(logFileName, 'a+') # Create file -> log - %date%.txt
print_write("[SERVER] Log created")
while True:
s.listen(1)
conn, addr = s.accept()
data = conn.recv(BUFFER_SIZE)
if data == "Comms Shutdown":
print_write("------ REMOTE SHUTDOWN ------")
conn.close()
raise SystemExit
else:
print_write("[COMMS] " + str(addr) + " says: " + data)
log.close()
Sorry if it's very messy and confusing but i don't have much time to finish this project, if you have any question just ask.
For the client side I don't have much but here, I'll give you this:
import socket
HOST = '10.0.0.16' # The remote host
PORT = 8080 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:
msg = raw_input()
s.sendall(msg)
print msg
I know it doesn't work, it's just to give you an idea of what I need.
Thank you in advance.
The problem is, that you only read the first message from each open connection before moving on to the next. The accept() methods waits for a new connection and gives you the information needed when a new one comes in. the recv() method on the other hand, receives data from a existing connection and waits if there is none. If you want to receive multiple messages from a single client, you can just wait for the first connection and then wait for data with recv(). This could look like this:
s.listen(1)
conn, addr = s.accept()
while True:
data = conn.recv(BUFFER_SIZE)
if data == "Comms Shutdown":
print_write("------ REMOTE SHUTDOWN ------")
conn.close()
raise SystemExit
else:
print_write("[COMMS] " + str(addr) + " says: " + data)
If you want to be able to also manage multiple clients, you will have to create a thread for each one from a while loop waiting for new connections. This is a bit more complicated:
def client_handler(conn):
while True:
data = conn.recv(BUFFER_SIZE)
if data == "Comms Shutdown":
print_write("------ REMOTE SHUTDOWN ------")
conn.close()
raise SystemExit
# this will kill the server (remove the line above if you don't want that)
else:
print_write("[COMMS] " + str(addr) + " says: " + data)
while True:
s.listen(1)
conn, addr = s.accept()
recv_thread = threading.Thread(target=client_handler, args=(conn, ))
recv_thread.start()
All this code is untested. Be aware, that I omitted the logging part and the socket creation part as well as all imports.

blocking recv() returns empty line instead of actual data

I'm working on a python client which is supposed to converse with a C programmed server. For now it just answers a few recognised commands with "ok" (the server part works when I test it with netcat as the client). But my python client only gets the ok 1 out of four times (and empty lines the rest of the time). I don't get why as the socket is set as blocking so I figure it does receive something but I don't know what.
Here is what I have. "info" is just an object with a few strings stored in it, everything before the loop works and a bit simplified for readability : I'm just supposed to receive a welcome message then send back the team name of the connected player then receive a position.
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
sys.exit();
try:
remote_ip = socket.gethostbyname(info.host)
except socket.gaierror:
print "Hostname could not be resolved. Exiting"
sys.exit()
s.setblocking(1)
s.settimeout(60)
s.connect((remote_ip, info.port))
data = s.recv(1024)
print data
team = info.team + "\n"
s.sendall(team)
data = s.recv(1024)
print data
while 42:
msg = raw_input('>> ')
s.sendall(msg + "\n")
data = s.recv(1024)
if data == "":
break
else:
print data
s.shutdown(socket.SHUT_WR)
s.close()
It seems to me you do receive something : cast data to ascii with ord() to see it. My guess is that there's 3 unprintable lines before the "ok" in the response the server sends you. Just identify then catch them in a new loop.

create an echo server

I am new to python and trying to code. I want to create simple echo server ie whatever I input to the client will simply be echo back by the server and if the client user press enter without writing anything then the server will disconnects. It may be very simple but I lacks logic here, any help??
here is my code
#!/usr/bin/env python
import socket
import sys
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #create socket
s.bind(("0.0.0.0",12345)) #binding port
s.listen(1) #listening for only one client
print "I am listening..."
conn,addr=s.accept() #accept the connection
conn.send("\nEnter your name.\n")
data = conn.recv(2048)
print "Client name is : ",data
conn.send("Now each word you typed will be echo back to you.\n")
while len(data)>0:
data=conn.recv(2048)
if data == '':
sys.exit()
else:
conn.send(data)
The result will contain a newline, but you can simply call str.strip to filter that out:
conn.send("\nEnter your name.\n")
data = conn.recv(2048)
if not data.strip():
print('Please enter a name')
return 1
print("Client name is : ", data)

Where is the right place to close a server socket (Python)

I have a server program that can maintain connection with multiple clients. I want to be able to close the socket in response to the message CLOSE by client, or for some other reason. The problem is that the server is stuck on the accept() method and does not care if I close the socket in some other place.
I can use some flag in the main server while, and close the socket after this while, however that means I will have to connect to the server myself after the client request, in order for the while condition to be checked, which smells like really terrible programming.
The code:
import socket
import sys
from thread import *
HOST = '' # Symbolic name meaning all available interfaces
PORT = 9992 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
#Bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error , msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
#Start listening on socket
s.listen(10)
print 'Socket now listening'
#Function for handling connections. This will be used to create threads
def clientthread(conn):
#Sending message to connected client
conn.send('Welcome to the server. Type something and hit enter\r\n') #send only takes string
data=''
#infinite loop so that function do not terminate and thread do not end.
while True:
#Receiving from client
data += conn.recv(1024)
print data
if data == 'CLOSE':
global s
conn.sendall('You have requested to destroy the connection...')
conn.close()
s.close()
return
if data.find('\n') != -1:
conn.sendall('OK...' + data + '\r\n')
data=''
#now keep talking with the client
while 1:
#wait to accept a connection - blocking call
try:
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
#start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.
start_new_thread(clientthread ,(conn,))
except:
print 'socket issue sorry'
break

Categories

Resources