i am having trouble and a lot of questions about socket programming attached code below ( all parts have been taken from the and written together) i am trying to send mouse data to the client ,howver getting the error:
Traceback (most recent call last):
File "srvr.py", line 29, in <module>
serv.sendall(status)
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
TypeError: must be string or buffer, not int
Questions: 1.how do we send data over sockets other then strings or specifically without the .send("...") statement .continously changing data?? 2.what things should be kept in mind when sending stream of data?? 3.code written here is a mess, would gladly appreciate help to teach some code sense into me
Thank YOu
Code: server side:
from socket import * #import the socket library
##let's set up some constants
HOST = '' #we are the host
PORT = 29876 #arbitrary port not currently in use
ADDR = (HOST,PORT) #we need a tuple for the address
BUFSIZE = 4096 #reasonably sized buffer for data
## now we create a new socket object (serv)
## see the python docs for more information on the socket types/flags
serv = socket( AF_INET,SOCK_STREAM)
##bind our socket to the address
serv.bind((ADDR)) #the double parens are to create a tuple with one element
serv.listen(5)
print 'listening...'
conn,addr = serv.accept() #accept the connection
print '...connected!'
mouse = file('/dev/input/mouse0')
while True:
status, dx, dy = tuple(ord(c) for c in mouse.read(3))
def to_signed(n):
return n - ((0x80 & n) << 1)
dx = to_signed(dx)
dy = to_signed(dy)
conn.send(status)
conn.close()
client:
##client.py
from socket import *
HOST = 'localhost'
PORT = 29876 #our port from before
ADDR = (HOST,PORT)
BUFSIZE = 4096
cli = socket( AF_INET,SOCK_STREAM)
cli.connect((ADDR))
data = cli.recv(BUFSIZE)
while data != '':
print data
cli.close()
2 Answers 2
While transferring data over network, it is very usual to pack it according to the big-endian byte order. Even though you have only three separates bytes at a time, and thus byte ordering doesn't matter, I still prefer to pack and unpack simply because it is a common way to communicate. Also, a common thing to do, when receiving network data, is to check whether you actually received the amount you were expecting, otherwise you have to request for more data. For simplicity, consider the following function for that:
def recv(sock, size):
data = ''
to_receive = size
while to_receive > 0:
data += sock.recv(to_receive)
to_receive = size - len(data)
return data
Now, what is lacking in your code is a common protocol. The client is acting as a receiver of raw meaningless data. Instead, it should be acting as a receiver of triplets. Besides that, I suggest to let the client request how many triplets he wants. Taking this into consideration, that is how I would change your client code to:
import sys
import socket
import struct
serv_host = ''
serv_port = 29876
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((serv_host, serv_port))
# Tell the server how many triplets I want.
amount = int(sys.argv[1])
s.sendall(struct.pack('!i', amount))
pack_size = struct.calcsize('!bbb')
while amount:
status, dx, dy = struct.unpack('!bbb', recv(s, pack_size))
print status, dx, dy
amount -= 1
s.close()
Now the server also needs to respect this newly imposed protocol. Note that a negative value effectively makes the client receive infinite triplets, that is intentional. Here is the modified server:
import socket
import struct
def to_signed(n):
return n - ((0x80 & n) << 1)
mouse = open('/dev/input/mouse0')
host = ''
port = 29876
backlog = 5
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host, port))
s.listen(backlog)
print 'Listening'
while True:
client, address = s.accept()
# Obtain the number of triplets the client wants.
amount = struct.unpack('!i', recv(client, 4))[0]
while amount: # Send the triplets as they become available.
status, dx, dy = map(ord, mouse.read(3))
dx, dy = to_signed(dx), to_signed(dy)
print status, dx, dy
client.sendall(struct.pack('!bbb', status, dx, dy))
amount -= 1
client.close()
1 Comment
You need to convert the type of the data that you are sending to a string or a buffer. The error message is quite clear. You need to do conn.send(str(status)) instead. You shouldn't need to "continuously" change data, you should only have to do it once, to a str object. To control what is in this str object if you are ever using your own class, you might define a __str__ method.
2 Comments
status being set to 2), send(str(status)) will send something like \x32\x00, where the other side may be waiting for \x00\x02 or \x02\x00 (depending on your protocol's byte order agreement).pack in the struct module.
structmodule. If you want to continuously send data from some device, the common approach is to first let the client request that. Then the server starts sending the data.