I'm trying to send a stream of images across http using a "persistent" connection. I have keep-alive in the header and so does the client (firefox) but I dont know how to send the second request or how to wrap it.
I've read the rfc. I've also wiresharked the connection while looking at a streaming service just like the one I'm trying to duplicate. I dont see any http messages going back and forth as the data is streamed (mjpg streamer)
So My question is this, what is required to send back to client in a http persistent connection ? If I just send fully formed http responses or just jpg data the client disconnects. If I wait for the client to send more data before sending the second image the client never sends anything.
import socket
import sys
import time
import binascii
from thread import *
HOST = '' # Symbolic name meaning all available interfaces
PORT = 9998 # Arbitrary non-privileged port
in_file = open("picture.jpg", "rb") # opening for [r]eading as [b]inary
testJpg = in_file.read() # if you only wanted to read 512 bytes, do .read(512)
in_file.close()
in_file = open("picture2.jpg", "rb") # opening for [r]eading as [b]inary
testJpg2 = in_file.read() # if you only wanted to read 512 bytes, do .read(512)
in_file.close()
OddNumber = 0
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 , 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):
global OddNumber, testJpg, testJpg2
OddNumber = 0
# get data from the client (assume its a http get request)
data = conn.recv(1024)
print("\r\n Got1: "+str(len(data)))
#time.sleep(.05)
while OddNumber < 30:
# create a new reply
reply = "HTTP/1.0 200 OK\r\n"
reply += "Server: MJPG-Streamer/0.2\r\n"
reply += "Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n"
reply += "Pragma: no-cache\r\n"
reply += "Content-type: image/jpeg\r\n"
# add in the content len
if OddNumber % 2 == 0:
reply += "Content-Length: "+str(len(testJpg))+"\r\n"
else:
reply += "Content-Length: "+str(len(testJpg2))+"\r\n"
# add the keep alive portion
reply += "Connection: Keep-Alive\r\n"
# I think we need this
reply += "\r\n"
# I use this toggle to switch between different images so if it does "stream" i'll be able to see it
# flipping these images
if OddNumber % 2 == 0:
reply += testJpg
else:
reply += testJpg2
# after the image
reply += "\r\n"
conn.sendall(reply)
OddNumber += 1
print("\r\n OddNum: "+str(OddNumber))
data = conn.recv(1024)
print("\r\n Got1: "+str(len(data)))
print(str(data))
#time.sleep(.05)
#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()
Apart from that I'm wondering if the persistent connection will even work for me. I'm developing a embedded device that is hosting the images, similar to a ipcamera. But I need to be able to send different URL's back to the device while it is sending me images. Is this possible on the same port ?
Someone requested I show whats in my http response. It is what you see in the python script. Its a valid http response and it works fine if I set
Connection: Keep-Alive\r\n"
to
Connection: close\r\n"
I guess my question is, what do you have to do in a persistent connection. Will the client send more "get" requests or is the server expected to stream some data ? At least firefox only sends one "get" request and then I send the response with a image but then what has to happen next to keep it going ?
Thanks for all the help so far.
I'm afraid that's because you use the same socket object in both client and server. Can you separate your code into two files? One file for server and the other for client (means your clientthread function).
In HTTP, when client get an HTTP response with 'keep-alive', it will hold TCP connection no matter what kinds of data you send.
Related
I can't understand why socket recv doesn't return. I have a client application that send string to a server. The client is executed in a terminal. This is the code
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "Enter client sender"
try:
client.connect((target, port))
if len(buffer):
client.send(buffer)
while True:
print "Enter loop"
recv_len = 1
response = ""
while recv_len:
print "Enter loop 2"
data = client.recv(4096)
print "Afer recv"
recv_len = len(data)
print recv_len
response += data
if recv_len < 4096:
break
print response,
buffer = raw_input("")
buffer += "\n"
client.send(buffer)
except:
print "[*] Exception Exiting"
client.close()
But the "After recv" label is never reached. Why? Can you help me? What is wrong?
Your code is generally correct, although bufferis a built-in type and you should avoid using it as a variable name (but it will still work if you do).
On a blocking socket (the default state), recv will block until there is some data available for reading. Make sure the other endpoint is sending (and flushing to the socket) a response.
You might find tcpdump or Wireshark useful to see the packets actually being transmitted. Also, I suggest you use nc or a similar generic TCP socket tool to debug this. E.g., nc -4 -l localhost PORT (-4 because your AF_INET implies IPv4).
I'm trying to develop a chat program in python. I want it to have multiple clients so I'm using threading to handle this. However when I try to send the message to all connected clients, the server only sends it to the client which sent the message. I'm not sure if I'm just missing something obvious but here is the code for the server:
import socket
from thread import *
host = '192.168.0.13'
port = 1024
users = int(input("enter number of users: "))
def clienthandler(conn):
while True:
data = conn.recv(1024)
if not data:
break
print data
conn.sendall(data)
conn.close()
serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversock.bind((host, port))
serversock.listen(users)
for i in range(users):
conn, addr= serversock.accept()
print 'Connected by', addr
start_new_thread(clienthandler, (conn,))
And here is the code for the client:
import socket
host = '192.168.0.13'
port = 1024
usrname = raw_input("enter a username: ")
usrname = usrname + ": "
clientsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsock.connect((host, port))
while True:
x = raw_input('You: ')
x = usrname + x
clientsock.sendall(x)
data = clientsock.recv(1024)
print data
The "all" in sendall means that it sends all of the data you asked it to send. It doesn't mean it sends it on more than one connection. Such an interface would be totally impractical. For example, what would happen if another thread was in the middle of sending something else on one of the connections? What would happen if one of the connections had a full queue?
sendall: Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Unlike send(), this method continues to send data from string until either all data has been sent or an error occurs. None is returned on success. On error, an exception is raised, and there is no way to determine how much data, if any, was successfully sent. -- 17.2. socket
You can try by pulling up the list of users, and iterating through it, and doing an individual send of the same message, though, unless you are the administrator and want to broadcast a warning, this functionality would be pretty mundane.
I have server and client code in python in which client sends a request message to server and wait for the response. I have the server code to close the connection when the client doesn't send a proper request. When the server closes the request, the client still is listening forever for the response.
Below is the code
server.py
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((host, port))
s.listen(1)
while True:
c, addr = s.accept()
# Receive request
data = c.recv(1024)
if data != 'something'
c.close()
else
c.sendall("message"+"End")
c.close()
s.close()
Client.py
End='End'
def recv_end(the_socket):
# Snippet from http://code.activestate.com/recipes/408859-socketrecv-three-ways-to-turn-it-into-recvall/
total_data=[];data=''
while True:
data=the_socket.recv(8192)
if End in data:
total_data.append(data[:data.find(End)])
break
total_data.append(data)
if len(total_data)>1:
#check if end_of_data was split
last_pair=total_data[-2]+total_data[-1]
if End in last_pair:
total_data[-2]=last_pair[:last_pair.find(End)]
total_data.pop()
break
return ''.join(total_data)
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((host, port))
s.send("some_request")
data = s.recv_end(1024)
print "<---- " + str(data)
s.close()
I'm new to python and wondering if there is a way for the client to know that the server closed the connection and terminate.
I understand that the client would disconnect if I use normal s.recv(1024). But in my case, I need to send large data to the client so I have used a different function I found from http://code.activestate.com/recipes/408859-socketrecv-three-ways-to-turn-it-into-recvall/.
Is it like the server sends a empty string reply during the close of a connection and in my case, it would send a empty string without the end limiter and hence the client is listening forever ?
When you have a loop with recv or anything that reads from a socket or a pipe, you should stop reading as soon as you get a buffer with len 0 :
while True:
data=the_socket.recv(8192)
if len(data) == 0: break
...
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.
Following is the code which listens on a port for HTTP requests and sends the request packet to the server running on port 80, gets the response and sends the data back to the client. Now, everything is executing fine but the following line of code :
data = req_soc.recv(1024)
is taking too much time to execute and I have observed that, it takes long time to execute when it is going to/has received the last packet. I have also tried the same code using select.select() but the results are the same. Since I want to handle the data (raw) that is coming from the client and the actual HTTP server, I have no other choice than using sockets.
import socket
import thread
def handle_client(client):
data = client.recv(512)
request = ''
request += data
print data
print '-'*20
spl = data.split("\r\n")
print spl[0]
print spl[1]
if len(request):
req_soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
req_soc.connect(('localhost', 80))
req_soc.send(request)
response = ''
data = req_soc.recv(1024)
while data:
response += data
print 1
data = req_soc.recv(1024)
req_soc.close()
print response
if len(response):
client.send(response)
client.close()
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 4422))
server.listen(5)
print("Server is running...\n")
MSGLEN = 1024
while 1:
client, address = server.accept()
thread.start_new_thread(handle_client, (client, ))
Clients can do multiple commands (eg: GET) within one connection. You cannot wait for the client to send all the commands because based on what you return it could request more (eg: images of a web page). You have to parse the parts (commands) of request, find the boundary, forward that request to the server and write back the answer to the client. All this in a way that doesn't block on reading the client.
I'm not sure what's the best way to do this in python, but if you spend 5 minutes of googling you'll find a perfect HTTP proxy library.