Client and Server unable to exchange data python - python

I'm using python 3.3.this is Server.py.Everything is fine both server and client are able to connect
something might be wrong in here 'tcpcli.send('[%s]%s'%(bytes(ctime(),'utf-8'),data))'.help me out
from socket import *
from time import ctime
HOST=''
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)
tcp=socket(AF_INET,SOCK_STREAM)
tcp.bind(ADDR)
tcp.listen(5)
while True:
print('waiting for connection')
tcpcli,addr=tcp.accept()
print('...connected from:',addr)
while True:
data=tcpcli.recv(BUFSIZ)
if not data:
break
tcpcli.send('[%s]%s'%(bytes(ctime(),'utf-8'),data))
tcpcli.close()
tcp.close()
This is CLient.py
from socket import *
HOST='127.0.0.1'
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)
tcpcli=socket(AF_INET,SOCK_STREAM)
tcpcli.connect(ADDR)
while True:
data=input('>')
if not data:
break
tcpcli.send(data)
data=tcpcli.recv(BUFSIZ)
if not data:
break
print (data.decode('utf-8'))
tcpcli.close()
When i'm running both they are working fine except I'm unable to send any data from client.
I'm getting this error message.
tcpcli.send(data)
TypeError: 'str' does not support the buffer interface

You are using Python3. This means that, when using the CLI, input() will return a str object (equivalent to python2 unicode). It contains an internal representation of the unicode codepoints of the characters you entered. To send the data over a byte stream interface (such as pipes, sockets, …), you have to convert it to a bytes object. This is easily done by picking an encoding, such as UTF-8, and doing something like this:
data_raw = data.encode("utf-8")
tcpcli.send(data_raw)
You will have to adapt your servers code similarily, by first decoding the data you received from the client and reencoding it after you did string operations on it:
data_decoded = data.decode("utf-8")
reply = '[%s]%s' % (ctime(), data_decoded)
tcpcli.send(reply.encode("utf-8"))

You are building unicode strings, not byte strings, and the socket interface doesn't support unicode strings. You'll need to encode the result of the string interpolation:
tcpcli.send(bytes('[%s]%s' % (ctime(),data), 'utf-8'))

Related

How to check if socket connection is working and buffering or is the request incorrect?

I have been trying to figure this out and can't seem to wrap my head around it.
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server = '192.168.1.7'
port = 8000
buffer_size = 4096
request = '1|gkdgdfg49|sdfsdfsd*|sdsfsf*|'+server
request = request.encode()
s.connect((server,port))
s.send(request)
x = s.recv(buffer_size)
The documentation for the server side is:
https://www.sharekhan.com/Upload/General/TradeTigerAPIForClient.pdf
The log of api server shows:
[I] "API Client Socket Connected with error Code=0"2018-09-22 16:07:23.555+05:30
[I] "Hurraay You have Connected."2018-09-22 16:07:23.555+05:30
[I] "Received Bytes Count = 49 Data Length = 1801944113 Thread State = Background, WaitSleepJoin , Queue Count = 0"2018-09-22 16:07:23.555+05:30
[I] "API Client Request Data Length 1801944113 bytes needs to read"
2018-09-22 16:08:21.984+05:30
[I] "Received Bytes Count = 49 Data Length = 1801944113 Thread State = Background, WaitSleepJoin , Queue Count = 0"
2018-09-22 16:08:21.984+05:30
[I] "API Client Request Data Length 1801944113 bytes needs to read"|Reserved = |
Is the request correct? Is the data being transferred?
If I rerun
s.send(request)
x = s.recv(buffer_size)
Nothing happens. The interpreter is stuck at running the above two lines.
I would appreciate any help. Very new to `sockets and the documentation is not very helpful.
As I pointed out in your other question, this is a binary protocol.
You're sending it ASCII text. Note that big number (1801944113), when interpreted as text, is equal to 'kg|1'. This is (the big-endian ordering of) the first four characters you sent it. In other words, it's taken the first four bytes you sent it, interpreted them as a binary value, and is now using it as the message length value -- which is obviously all wrong.
You need to use the python struct module's pack and unpack methods to encode and decode binary values to build up your buffer.
That would look something like this:
import struct
trans_code = 1 # LOGIN
login_id = b'MyName'
mpassword = b'MyPass'
tpassword = b'MyTradingPass'
my_ip = b'192.168.1.31' # No idea what the point of this is
reserved = b''
msg_length = 196
msg_buffer = struct.pack("!IH30s20s20s20s100s", msg_length, trans_code,
login_id, mpassword, tpassword, my_ip, reserved)
assert len(msg_buffer) == msg_length
print("Login request to send '{}'".format(msg_buffer))
You will need to learn to use the struct module. It's well-specified in the python documentation.
Your results (in particular that big number) establish that the server is expecting numeric fields to be encoded in big-endian byte order (AKA "network byte order").

'in' operator in Python not behaving as expected on the same string

I am using Python2.7 and I am facing a rather peculiar problem in a program where I receive data over a socket and I check for two strings in the data received. The program is behaving awkwardly, one check returns true while other false, which I am not able to understand, why. Please help if I am doing something wrong here. Find the code below:
import socket
import sys
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('172.16.16.121', 10000)
print >> sys.stderr, 'starting as server on %s port %s' % server_address
sock.bind(server_address)
sock.listen(1)
while True:
print >> sys.stderr, 'waiting for a connection'
connection, client_address = sock.accept()
try:
while True:
data = connection.recv(1024)
if data:
print "Status 2: " + str("#" in data)
if "#" in data:
input_str = "".join(data)
print input_str
print "Status: " + str("Restart" in str(input_str))
if "RestartService".lower() in str(input_str).lower():
print "Kill them all"
except Exception,e:
sock.close()
connection.close()
finally:
# Clean up the connection
sock.close()
connection.close()
Output registered on console is:
starting as server on 172.16.16.121 port 10000
waiting for a connection
Status 2: True
RestartService#
Status: False
When I use repr(input_str) I get:
'\x00R\x00e\x00s\x00t\x00a\x00r\x00t\x00S\x00e\x00r\x00v\x00i\x00c\x00e\x00#'
You are receiving UTF-16 encoded data. Decode this to Unicode strings first; with the \x00 bytes coming first this is using UTF-16 in big-endian order:
input_str = data.decode('utf-16-be')
if u"restartservice" in input_str.lower():
Note that I used a Unicode string literal (u'...') to test against the decoded text; that way you avoid implicit decoding and encoding, which can lead to further exceptions if one of the two operands doesn't cleanly decode or encode as ASCII.
Demo:
>>> input_str = '\x00R\x00e\x00s\x00t\x00a\x00r\x00t\x00S\x00e\x00r\x00v\x00i\x00c\x00e\x00#'
>>> input_str.decode('utf-16-be')
u'RestartService#'
>>> 'restartservice' in input_str.decode('utf-16-be').lower()
True
You may want to read up on what Unicode is, and how to best handle this in Python code; I strongly recommend the following articles:
Pragmatic Unicode by Ned Batchelder
The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) by Joel Spolsky
The Python Unicode HOWTO

Sending an array over UDP connection

I want to send an array using a UDP connection. When I use the sendto function, it complains that it must be a string. Is there any way around this?
Thanks
You must serialize your data (in this case is an array) before sending it. Then in receiver, you will deserialize to get the original data.
You can do it in Python, using pickle or cPickle module:
import cPickle as p
# Sender
data_str = p.dumps(array)
sock.sendto(data_str, addr)
# Receiver
data,addr = sock.recvfrom(buf)
data_origin = p.loads(data)

How can I transfer binary data over xmlrpc (python)?

As the name xmlrpc implies, this transfer protocol relies on XML to carry data, and cannot transfer binary data, or non-printable ASCII-characters (\n, \b, chr(2),...) [or can it?].
I would like to know if there is a way to transfer a character string safely from a client to a server with minimal impact on the coding (i.e. ONLY on the client side). I tried the xmlrpclib.Binary class but this only seem to work with files.
Testcode, server.py:
def output(text):
print "-".join([str(ord(x)) for x in text])
from SimpleXMLRPCServer import SimpleXMLRPCServer
server = SimpleXMLRPCServer(('localhost', 1234))
server.register_function(output)
server.serve_forever()
client.py:
import xmlrpclib
device = xmlrpclib.ServerProxy("http://localhost:1234/RPC2")
device.output(".\n."+chr(2))
Expected outcome:
46-10-46-2
Seen outcome (on server side):
xmlrpclib.Fault: <Fault 1: "<class 'xml.parsers.expat.ExpatError'>:not well-formed (invalid token): line 7, column 1">
I think the expected answer was using xml-rpc base64 type. In python, on client side, you have to manually specify that a string contains binary data, using the xmlrpclib.Binary type.
import xmlrpclib
device = xmlrpclib.ServerProxy("http://localhost:1234/RPC2")
device.output(xmlrpclib.Binary(".\n."+chr(2)))
You could try encoding your binary data in a text format in the client and decoding it back into binary in the server. One encoding you could use is base64.
In your client:
import xmlrpclib
import base64
device = xmlrpclib.ServerProxy("http://localhost:1234/RPC2")
device.output(base64.b64encode(".\n."+chr(2)))
In your server:
import base64
def output(text):
print "-".join([str(ord(x)) for x in base64.b64decode(text)])
from SimpleXMLRPCServer import SimpleXMLRPCServer
server = SimpleXMLRPCServer(('localhost', 1234))
server.register_function(output)
server.serve_forever()

Sending and Receiving arrays via Sockets

Is it possible to send an array through UDP Sockets using Python? I am using Python 2.5 and trying to send a simple array but it's not working. It can send the array successfully but when I try to print it with an item of the array the program crashes. I'm not sure what the error is as I take the precaution of converting the data into an array but it's not working. Hope I explained the problem as clearly as possible. I would appreciate the help!
# Client program
from socket import *
import numpy
from array import*
# Set the socket parameters
host = "localhost"
port = 21567
buf = 4096
addr = (host,port)
# Create socket
UDPSock = socket(AF_INET,SOCK_DGRAM)
def_msg = "===Enter message to send to server===";
print "\n",def_msg
a = array('i',[1,3,2])
# Send messages
while (1):
data = raw_input('yes or now')
if data!= "yes":
break
else:
if(UDPSock.sendto(a,addr)):
print "Sending message"
# Close socket
UDPSock.close()
# Server program
from socket import *
# Set the socket parameters
host = "localhost"
port = 21567
buf = 4096
addr = (host,port)
# Create socket and bind to address
UDPSock = socket(AF_INET,SOCK_DGRAM)
UDPSock.bind(addr)
# Receive messages
while 1:
data,addr = UDPSock.recvfrom(buf)
L = eval(data)
if not data:
print "Client has exited!"
break
else:
print "\nReceived message '", L[1],"'"
# Close socket
UDPSock.close()
eval is doing something completely different than what you think.
To send data over network, you need to serialize it into an array of bytes, then deserialize it back. In Python, serialization of most objects can be done via pickle module:
if (UDPSock.sendto( pickle.dumps(a), addr)):
Deserialization:
data,addr = UDPSock.recvfrom(buf)
L = pickle.loads(data)
print repr(L) # prints array('i', [1, 3, 2])
I would personally use tostring and fromstring since the built-in serialization methods are many times faster and pickle may not support NaN, Inf and other undefined values.
You're trying to send a python object through a socket, it is normal that it doesn't work, you can't send objects in a socket, objects are not data, they are the representation of some data in a given programming language. You need to "translate" your object to data and re-create the object from the data on the other socket's side. One way to do this would be with the pickle module.
On the client side, you "pickle" the object:
data = pickle.dumps(my_array)
And on the server side, you "unpickle" the received data:
my_array = pickle.loads(received_data)
You could try to pickle the array. Pickle is a python library to en- and decode python objects. It is able to do much more, but it is definitely sufficient to fulfill your task:
on the sender side you pickle the object to a string:
pickled_string = pickle.dumps(a)
on the receiver side you unpickle the object:
a = pickle.loads(received_string)
# a is now your sent array
It has been a while since this question was asked, but I thought it's worth sharing the jsonsocket library. It makes it really easy to send strings, lists and dictionaries over sockets. It can handle big amounts of data efficiently. And you don't need to do any manual serialization/deserialization. Under the hood, it serializes the data as JSON strings on the client, and deserializes it on the server.
If you don't need UDP specifically, try zmqObjectExchanger (https://github.com/ZdenekM/zmq_object_exchanger). It wraps pickle and zmq to transfer python objects over TCP.

Categories