1

I'm writing a TCP client/server and I've been hitting this broken pip error in the latter part of the code. I have been unable to isolate the cause due to a limited understanding of Python and socket programming and I am, therefore, unable to fix the problem. I'm going to have to include all the code as there might be some sort of conflict causing this issue that I am unaware of, sorry for the long post.

I have marked where I encounter the issue below, everything up to this point runs fine.

Server Code:

import os
from socket import *
import urllib
import time

HOST = '' #We are the host
PORT = 29876
PORT2 = 29877
ADDR = (HOST, PORT)
ADDR2 = (HOST, PORT2)

BUFFSIZE = 4096


serv =  socket( AF_INET,SOCK_STREAM)
serv.bind(ADDR,)
serv.listen(5)
print ('listening... \n')


conn,addr = serv.accept()
print (conn,addr)
print ('...connected \n')

with open(os.path.expanduser("~/.ssh/id_rsa.pub")) as f:
    key = f.read()
    conn.sendall(key)
print("Key Sent... \n")


data = conn.recv(BUFFSIZE)
with open('ip.txt', 'w') as myfile:
    myfile.write(str(data))

with open("ip.txt", "r") as myfile:
    ip=myfile.read().replace('\n','')
print("The client IP is: " + ip + "\n")

conn.close()


ver = socket(AF_INET,SOCK_STREAM)
ver.bind(ADDR2,)
ver.listen(5)
print('listening...\n')

build,addr = ver.accept()
print (build,addr)
print('...connected\n')

#Get Version
version = urllib.urlopen("http://p.b.r.com/pa/b/latest.txt")
print(version.read())

#IT IS SENDING THIS LAST PIECE OF DATA THAT CAUSES THE BROKEN PIPE ERROR
version = str(version.read())
ver.send(version)

Client Code :

from socket import *
from winreg import *
import os
import socket
import platform
import string
import time

#Detect OS
os = platform.system()
print("Your system is running "+ os)

#Set Host address and port
HOST = 'xxx.xxx.xxx.xxx'
PORT = 29876
PORT2 = 29877
ADDR = (HOST,PORT)
ADDR2 = (HOST, PORT2)
BUFFSIZE = 4096


cli = socket.socket( AF_INET, SOCK_STREAM)
cli.connect(ADDR,)


#Get and send IP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("gmail.com",80))
ip = ((s.getsockname()[0]))
ip = ip.encode('utf-8')
cli.send(ip)
print("IP Sent... \n")

#Set received key to write to known hosts
data = cli.recv(BUFFSIZE)
with open('C:\cygwin\home\scollins\.ssh\known_hosts', 'w') as myfile:
    myfile.write(str(data,'utf-8'))
print("Key Saved To Known Hosts")

#Close opened sockets
s.close()
cli.close()


ver = socket.socket( AF_INET, SOCK_STREAM)
ver.connect(ADDR2,)

#Get version/build number
if os == "Windows":
    #Connect to the registry
    regKey = ConnectRegistry(None, HKEY_LOCAL_MACHINE)
    subKey = OpenKey(regKey, r"SOFTWARE\R\R Client")
    buildno = QueryValueEx(subKey, "Version")
else:
    if os == "Darwin":
        buildno = open("\Library\R\buildno")
    else:
        if os == "Linux":
           buildno = open("\r\buildno")


print("You are running software build number " + str(buildno))


#Receive and write server software version to file. Read file and compare build number
data = ver.recv(BUFFSIZE)

#THIS NEXT PRINT COMMAND RETURNS NOTHING WHICH I ASSUME IS DUE TO NOTHING BEING RECEIVED DUE TO THE BROKEN PIPE
print(str(data))
with open('version.text', 'w') as myfile:
    myfile.write(str(data,'utf-8'))

with open('version.txt', 'r') as myfile:
    version = myfile.read()
print("The software on the server is version: " + version)

if buildno in version == True:
    print("Your sofware version is up to date")
else:
    print("Your software is out of date. Updating your software.")
    os.system('')

ver.close()

Thank you for any help provided.

Metagen
  • 41
  • 1
  • 2
  • 9

1 Answers1

2

Well, I don't have python3 installed here at work, but just from looking at the code, it looks like you are trying to send something with the server socket in the server part.

You call accept on ver:

build,addr = ver.accept()

Then you try to send on ver, instead of build:

ver.send(version)

Usually it works like this: On the server side, you have a "server" socket, that you call bind on and then accept, waiting for incoming connections. Every time a client connects, accept yields a socket to talk to this specific client ("client" socket). If all communication would go via the server socket, how could you have multiple clients and know which one you are "talking" to?

The second error in the code was, that version.read() was called to print the value and later again to send it. read() "consumes" the data, thus the second read() gave an empty result.

Also, you should call send() in a loop, checking its return value, to make sure all of the data is actually sent. Partial sends can happen.

Benjamin Maurer
  • 3,602
  • 5
  • 28
  • 49
  • Thank you for your quick reply and you were 100% correct. However, I have encountered another problem. The value of version is not being sent across, instead all that is received is an empty bytes marker (b' '). It may be worth noting that before converting version to a string to send that it is a tuple. – Metagen Feb 18 '13 at 15:40
  • Mh, no, look at the documentation again: http://docs.python.org/2/library/urllib.html you also do: version = urllib.urlopen("http://p.b.r.com/pa/b/latest.txt") print(version.read()) version is a file descriptor type object, on which you can perform a read() to get the data. You are trying to turn an object into a string, which does not have a string representation. Also, don't forget to accept and upvote if it solved your problem ;) – Benjamin Maurer Feb 18 '13 at 15:50
  • Also, whats up with the time.sleep(120)? – Benjamin Maurer Feb 18 '13 at 15:53
  • I would upvote if I had the reputation to haha. The reason I have print(version.read()) is because without that the version number would not print and instead I would get ">". I actually meant to remove that sleep command. It was only there because I thought that a connection may not have closed properly and I'd read the timeout for this can be up to 2 minutes, so I was hoping that waiting might fix the issue I was seeing. – Metagen Feb 18 '13 at 16:08
  • Thats what I'm saying about version.read. Later, you try to send str(version), but you should be transmitting whatever version.read() returns! – Benjamin Maurer Feb 18 '13 at 16:20
  • If you have problems reopening a socket or reusing a port, that's likely because the operating systems left it in "time wait" state. To avoid that, you can set a socket option. See the comments on the answer here: http://stackoverflow.com/questions/2351465/socket-shutdown-and-rebind-how-to-avoid-long-wait – Benjamin Maurer Feb 18 '13 at 16:21
  • Oh sorry, I hadn't realised that I hadn't updated my code here. It's been updated to what I am currently using which returns b' ' when sent which is the problem that I'm currently having. Also in the client script the os.system('') call will be used to call a bash script in case you're wondering why it's been left blank for the moment. – Metagen Feb 18 '13 at 16:28
  • I'm guessing here, but maybe you can't call .read() twice, because it's a "consuming read". Store it in a variable. Print it before the send to make sure it's well formed. Check the result of send, that's the bytes sent. Usually you have that in a loop, bc. sometimes you need multiple sends to send all the data. It's probably the read thing. Also, I don't think you need str() all the time. recv is supposed to return a string anyway. – Benjamin Maurer Feb 18 '13 at 16:43
  • Once again you were 100% correct about only being able to use .read() once. The str() was necessary however. Thank you so much for your help today. I've finally got this finished thanks to you. Much appreciated. – Metagen Feb 18 '13 at 17:00