Search code examples
pythonpython-3.xsocketsclient-server

Python 3.7: Error while sending a file through python socket


Using Python, I want to publish data to socket.
I written a client/server program in Python 3.7 to send a large csv file over the network. The client and server codes are given below.

Sample file:

$ cat datafile.csv
id,first_name,gender,car,money,city,country,jobtitle
1,Marline,Female,Ford,$4.94,Kanzaki,Japan,Food Chemist
2,Ker,Male,Lincoln,$3.46,Fort Beaufort,South Africa,Marketing Manager
3,Wallie,Male,Land Rover,$5.12,Eystur,Faroe Islands,Senior Quality Engineer
4,Deonne,Female,Ford,$9.72,Fontaínhas,Portugal,Social Worker
5,Barnaby,Male,Volkswagen,$0.60,Taoyuan,China,Web Developer I
6,Maximilian,Male,GMC,$1.19,Nowy Dwór Gdański,Poland,Engineer IV
7,Wake,Male,Buick,$5.08,Kazuno,Japan,Food Chemist
8,Truman,Male,Infiniti,$1.60,Içara,Brazil,Senior Quality Engineer
9,Mufi,Female,Ford,$7.55,Gununglajang,Indonesia,Actuary
10,Dniren,Female,Ford,$7.71,Yuyapichis,Peru,Software Consultant

Below are the client server program:

Client code:

$ cat client.py

import socket

HOST = 'server ip'        # The remote host
PORT = 42050              # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
f = open('/home/vijee/data/datafile.csv', 'rb')
print "Sending Data ...."  
l = f.read()
while True:      
    for line in l:
        s.send(line)    
    break
f.close()
print "Sending Complete"
s.close()

Server code:

$ cat server.py

import socket

HOST = 'local ip'         # server ip
PORT = 42050              # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
print "Server running", HOST, PORT
s.listen(5)
conn, addr = s.accept()
print'Connected by', addr

while True:
    data = "".join(iter(lambda:conn.recv(1),"\n"))       
    print data   
    if not data: break                

print "Done Receiving"
conn.close()

While executing client.py script I am getting the below error:

bash_shell:~$ python /home/vijee/data/python_code/server.py 
Server running localhost 9000
Connected by ('127.0.0.1', 42950)

bash_shell:~$ python /home/vijee/data/python_code/client.py 
Sending Data ....
Traceback (most recent call last):
  File "/home/vijee/data/python_code/client.py", line 12, in <module>
    s.send(line)    
TypeError: a bytes-like object is required, not 'int'

I know it is small mistake. But could not able to find the error.


Solution

  • l is a bytes object. From the documentation:

    While bytes literals and representations are based on ASCII text, bytes objects actually behave like immutable sequences of integer

    So when you write for line in l:, each value of line is a integer containing a single byte from the file. The argumentg to s.send() has to be bytes, not an integer. So you could use:

    s.send(bytes([line]))
    

    to convert the integer to a bytes object. Don't forget the [] -- the bytes constructor expects a sequence. If you just write bytes(line), it will create a bytes object whose length is line and the contents are all zero bytes.

    There's not really any reason for the loop that tries to send one byte at a time. Just use

    s.send(l)
    

    to send it all at once.

    BTW, the variable name line suggests that you think you're sending line by line, not byte by byte. That's not happening. Since you opened the file in binary mode, it doesn't have the notion of lines. And even if you'd opened it in text mode, l would be a string, not a sequence of lines; if you want a sequence of lines you should use f.readlines(), or for line in f:.