I've faced an odd problem and I cannot figure out what the reason is! Actually, I've written a simple server in Python which echos whatever the client enters. To test it, I connected to server by telnet, but as soon as I enter a character, it will become echoed! I do not know how to stop it! Actually I want to complete a word and after hitting the enter key, my server echos it.
Here is my simple server:
import socket
import sys
HOST = '' # Symbolic name meaning all available interfaces
PORT = 5000 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
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'
s.listen(10)
print 'Socket now listening'
#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])
while True:
data = conn.recv(1024)
reply = 'OK...' + data
if not data:
break
conn.sendall(reply)
conn.close()
s.close()
According to the telnet man page, the client attempts to enter linemode, and will fallback to character mode if the remote server doesn't support it:
Once a connection has been opened, telnet will attempt to enable the TELNET LINEMODE option. If this fails, then telnet will revert to one of two input modes: either “character at a time” or “old line by line” depending on what the remote system supports.
You can change your server-side code to handshake with the client for enabling line-by-line, or you can force the client to use an "old" line-by-line mode, where it buffers the characters locally, and sends them all at once.
To do the former, you should be able to send the following sequence of bytes after the initial connection as found here:
0x255 0x253 0x34
To do the latter, you can do (press ctrl right bracket first), which will enable this mode in the telnet client (assuming you are using the BSD telnet command - on Windows it may be different).
^]toggle localchars
Related
Right now, I'm trying to make a socket server in Python that takes input from a client, processes it, does whatever is need to be done, and then sends a message back to the client showing that it's done.
The problem I am having right now is that the system can't recognize a command that is sent by the client. I am currently using an if statement to compare strings. The data received is decoded into UTF-8. I don't see why the if statement can't compare them.
'''
Simple socket server using threads
'''
import socket
import sys
from thread import *
import cmd
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
databyte = conn.recv(1024)
reply = 'OK...' + data
data = databyte.decode('utf-8')
if data == 'light'
print 'light'
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()
Any help would be appreciated! Thank you in advance!
This code can create socket, connect to selected server and port, and print reply. I have a question, how can I listening to the port longer than one moment? E.g. I want listen to selected port for 20 seconds and print all packets which will come at this time. Is it possible with this code?
import socket
import sys
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error as msg:
print("Failed to create socket. Error code: " + str(msg[0]) + ' , Error message : ' + msg[1])
sys.exit();
print('Socket Created')
host = #server
port = #port
try:
remote_ip = socket.gethostbyname( host )
except socket.gaierror:
print('Hostname could not be resolved. Exiting')
sys.exit()
print('Ip address of ' + host + ' is ' + remote_ip)
s.connect((remote_ip , port))
print('Socket Connected to ' + host + ' on ip ' + remote_ip)
reply = s.recv(4096)
print(reply)
You could try setting the timeout for the socket should fit your requirement if I understand correctly that you just need to wait one time for 20 seconds.
s.settimeout(20)
reply = s.recv(4096)
Python Socket settimeout()
However you are not guaranteed to get all the data packets delivered at once. So as was mentioned in a comment, you should be looping. The way to do this would be to place the socket in nonblocking mode.
Outside of your loop, you need a buffer_variable that would hold the total results from the recv().
Prior to entering your loop, you would start a timer. Upon entering you loop you would begin calling recv() on the socket while saving the result in a local_variable. Each time you get something new in local_variable you append it to buffer_variable.
When the timer expires, you would then break the loop, and process your data from buffer_variable accordingly.
This is the sample socket at server side (taken from some website):
import socket
import sys
HOST = '' # Symbolic name, meaning all available interfaces
PORT = 10001 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
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'
#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])
conn.send("Test Messag")
s.close()
This is the code at client side:
import socket
s=socket.socket()
s.connect((ipaddress,port))
s.setblocking(1)
import time
counter = 0
while True:
print counter
chunk = s.recv(11,socket.MSG_WAITALL)
if not chunk:
raise Exception('Socket error')
print chunk
time.sleep(1)
counter += 1
The server side code runs on an amazon ec2 instance (based on the amazon linux ami)
When I terminate the instance I would expect that the recv method on the socket throws an error, but it does not. Whatever I do, it never throws an error. When I run the server side code in an ipython notebook and restart the kernel, the recv method unlocks and keeps returning empty strings (according to When does socket.recv() raise an exception? this should be in the case of a clean shutdown), but no error is thrown.
What could be the cause of this, I really need to have it throw an exception so I can notify the rest of my code that the server went down in order to start a new one.
When I terminate the instance I would expect that the recv method on the socket throws an error ...
When the server terminates it will do a clean shutdown of the socket, so you will get no exception on the client side. To get what you want you would have to implement some kind of shutdown message inside your application. Then you can distinguish a proper shutdown (with an explicit shutdown message) from just a socket close.
You are making only one tcp connection. You have to make multiple request.
import socket
import time
counter = 0
while True:
print counter
s=socket.socket()
try:
s.connect((ipaddress,port))
s.setblocking(1)
chunk = s.recv(11,socket.MSG_WAITALL)
except Exception as e:
print e
break
print chunk
time.sleep(1)
counter += 1
This may have been already answered but did not find anything or dont know what to search for. I have a socket server threaded for multiple clients (code below) and want the server to run code (ie. check the status of something) and then send a message to the clients. How do I go about doing this?
To clarify, I need to learn how to add a asynchronous task to this code so it can do checking and send a message to the clients if it needs to
Example: while there are clients connected I want the server to continually check a log file and if it changes and if so I want it to send a message to the clients
Server.py(working code)
from socket import *
import thread
BUFF = 1024
HOST = '127.0.0.1'# must be input parameter #TODO
PORT = 9999 # must be input parameter #TODO
def response(key):
return 'Server response: ' + key
def handler(clientsock,addr):
while 1:
data = clientsock.recv(BUFF)
if not data: break
print repr(addr) + ' recv:' + repr(data)
clientsock.send(response(data))
print repr(addr) + ' sent:' + repr(response(data))
if "close" == data.rstrip(): break # type 'close' on client console to close connection from the server side
clientsock.close()
print addr, "- closed connection" #log on console
if __name__=='__main__':
ADDR = (HOST, PORT)
serversock = socket(AF_INET, SOCK_STREAM)
serversock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serversock.bind(ADDR)
serversock.listen(5)
while 1:
print 'waiting for connection... listening on port', PORT
clientsock, addr = serversock.accept()
print '...connected from:', addr
thread.start_new_thread(handler, (clientsock, addr))
I have added below code server.py and this works for sending a status change message when log file changes.
import socket
import sys
import time
from thread import *
HOST = 'localhost' # Symbolic name meaning all available interfaces
PORT = 9999 # 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
data = conn.recv(1024)
#infinite loop so that function do not terminate and thread do not end.
while True:
logfile = open("serverlog.txt","r")
#Receiving from client
logfile.seek(0,2)
while True:
line = logfile.readline()
if not line:
time.sleep(0.1) # Sleep briefly
continue
reply = 'File Changed...Your Data' + 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()
To test it run this server.py in one command prompt and keep it open. something like this
> python server.py
Socket created
Socket bind complete
Socket now listening
And run a simple telnet from other cmd prompt to verify the connection
telnet localhost 9999
Replace localhost with IP. Type anything on these telnet connection and you should get response properly.
Also you can check on server.py cmd prompt for the connections made.
And as I mentioned, check this link.
Recently, I managed to create sockets on my PC and my Raspberry Pi to enable communication between both devices. Currently, the client is able to automatically send messages to the server. I was wondering, if it is possible to modify the scripts to send tcp data packets instead of purely text messages, as I would very much like to control the raspberry pi using my PC in the future without having the need to ssh/etc.
I've looked at some examples, but as I don't have much experience in writing my own scripts/codes, I'm not very sure how to go about doing this. I would appreciate if someone could guide me in the right direction with explanation and some examples if possible.
Anyway here is the server/client script I'm running at the moment:
Client:
import socket
import sys
import struct
import time
#main function
if __name__ == "__main__":
if(len(sys.argv) < 2) :
print 'Usage : python client.py hostname'
sys.exit()
host = sys.argv[1]
port = 8888
#create an INET, STREAMing socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print 'Failed to create socket'
sys.exit()
print 'Socket Created'
try:
remote_ip = socket.gethostbyname( host )
s.connect((host, port))
except socket.gaierror:
print 'Hostname could not be resolved. Exiting'
sys.exit()
print 'Socket Connected to ' + host + ' on ip ' + remote_ip
#Send some data to remote server
message = "Test"
try :
#Set the whole string
while True:
s.send(message)
print 'Message sent successfully'
time.sleep(1)
print 'Sending...'
except socket.error:
#Send failed
print 'Send failed'
sys.exit()
def recv_timeout(the_socket,timeout=2):
#make socket non blocking
the_socket.setblocking(0)
#total data partwise in an array
total_data=[];
data='';
#beginning time
begin=time.time()
while 1:
#if you got some data, then break after timeout
if total_data and time.time()-begin > timeout:
break
#if you got no data at all, wait a little longer, twice the timeout
elif time.time()-begin > timeout*2:
break
#recv something
try:
data = the_socket.recv(8192)
if data:
total_data.append(data)
#change the beginning time for measurement
begin=time.time()
else:
#sleep for sometime to indicate a gap
time.sleep(0.1)
except:
pass
#join all parts to make final string
return ''.join(total_data)
#get reply and print
print recv_timeout(s)
s.close()
Server:
import socket
import sys
from thread import *
HOST = '' # Symbolic name meaning all available interfaces
PORT = 8888
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
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'
s.listen(10)
print 'Socket now listening'
#Function for handling connections
def clientthread(conn):
#Sending message to connected client
conn.send('Welcome to the server. Receving Data...\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)
reply = 'Message Received at the server!\n'
print data
if not data:
break
conn.sendall(reply)
conn.close()
#now keep talking with the client
while 1:
#wait to accept a connection
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
#start new thread
start_new_thread(clientthread ,(conn,))
s.close()
socket.socket(socket.AF_INET, socket.SOCK_STREAM) already creates a connection that provides a reliable stream of bytes between two machines. This uses TCP, which is on top of IP and Ethernet. The latter two are package-based, while TCP creates a stream of continuous bytes on top of it. It also adds some error checking and error correction, so it is pretty reliable.
I honestly don't understand what you want to achieve with what you call "send packets". What you don't want to do is to create an implementation of TCP yourself, as that's a non-trivial task, so sending RAW packets is out. In general, even using TCP is already relatively low-level and should be avoided unless really necessary.
Using e.g. ZeroMQ you get a message-based interface that does all the transmission for you. It does so on top of TCP (or other transports) and adds more error correction for e.g. disconnects. There, you also have something like "packets", but those are independent of how many TCP or IP packets were required to send it underneath. If you don't want to implement a specific protocol, I'd suggest you use this framework instead of lowlevel TCP sockets.
Another simple alternative is to use HTTP, for which there is also existing code in Python. The downside is that it is always one side that initiates some communication and the other side only replies. If you want some kind of active notification, you either have to poll or use hacks like delaying an answer.
You are already sending data packets - those packets juts happen to contain text data at the moment. Try looking into pickle in the standard libraries and into pyro.