I have a simple network of two machines connected directly by cable (no switches, routers, or anything else). One of the machines is a radar, which continously multicasts image data. The other machine is a Windows PC, on which I want to receive that data.
For a first test, I have a simple Python script:
import socket
MULTICAST_GROUP = '239.0.17.8'
PORT = 6108
LOCAL_IF = '192.168.3.42'
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(1.0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((LOCAL_IF, PORT))
sock.setsockopt(
socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(MULTICAST_GROUP) + socket.inet_aton(LOCAL_IF)
)
while True:
try:
data, address = sock.recvfrom(64*1024)
except socket.timeout:
print 'timeout'
else:
print address, len(data)
If I run this from IDLE, it works fine. But if I run it stand-alone (from the command prompt, or double-click in Explorer), it doesn't receive any data; it only prints 'timeout' once a second.
I've been looking at Wireshark output to try to find the difference, but I've found none. Same data arrives, same membership request is sent (the membership is sent twice actually; is that normal?).
The datagrams are quite large (29504 bytes); could that be a problem?
What could be the big difference between running the script within or without IDLE? How can I make it always work ?
As Michele d'Amico suspected, the problem was a mis-configured firewall. Shame on me for not discovering that myself.
Related
I'm a beginner in the field of sockets and lately trying ti create a terminal chat app with that.I still have trouble understanding setblocking and select functions
"This is the code i have taken from a website i'm reading from and in the code if there is nothing in data, how does it mean that the socket has been disconnected and please also do explain what affect the setblocking in the server or the client does.I have read somewhere that setblocking allows to move on if the data has been fully not recieved,i'm not quite satisfied with the explaination.Please explain in simple words "
import select
import socket
import sys
import Queue
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(0)
server_address = ('localhost', 10000)
server.bind(server_address)
server.listen(5)
inputs = [ server ]
outputs = [ ]
message_queues = {}
while inputs:
readable, writable, exceptional = select.select(inputs, outputs, inputs)
for s in readable:
if s is server:
connection, client_address = s.accept()
connection.setblocking(0)
inputs.append(connection)
message_queues[connection] = Queue.Queue()
else:
data = s.recv(1024)
if data:
message_queues[s].put(data)
if s not in outputs:
outputs.append(s)
else:
if s in outputs:
outputs.remove(s)
inputs.remove(s)
s.close()
if there is nothing in data, how does it mean that the socket has been disconnected
The POSIX specification of recv() says:
Upon successful completion, recv() shall return the length of the message in bytes. If no messages are available to be
received and the peer has performed an orderly shutdown, recv() shall return 0. …
In the Python interface, return value 0 corresponds to a returned buffer of length 0, i. e. nothing in data.
what affect the setblocking in the server or the client does.
The setblocking(0) sets the socket to non-blocking, i. e. if e. g. the accept() or recv() cannot be completed immediately, the operation fails rather than blocks until complete. In the given code, this can hardly happen, since the operations are not tried before they are possible (due to the use of select()). However, the example is bad in that it includes output in the select() arguments, resulting in a busy loop since output is writable most of the time.
Short description:
Client sends server data via TCP socket. Data varies in length and is strings broken up by the delimiter "~~~*~~~"
For the most part it works fine. For a while. After a few minutes data winds up all over the place. So I start tracking the problem and data is ending up in the wrong place because the full thing has not been passed.
Everything comes into the server script and is parsed by a different delimiter -NewData-* then placed into a Queue. This is the code:
Yes I know the buffer size is huge. No I don't send data that kind of size in one go but I was toying around with it.
class service(SocketServer.BaseRequestHandler):
def handle(self):
data = 'dummy'
#print "Client connected with ", self.client_address
while len(data):
data = self.request.recv(163840000)
#print data
BigSocketParse = []
BigSocketParse = data.split('*-New*Data-*')
print "Putting data in queue"
for eachmatch in BigSocketParse:
#print eachmatch
q.put(str(eachmatch))
#print data
#self.request.send(data)
#print "Client exited"
self.request.close()
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
t = ThreadedTCPServer(('',500), service)
t.serve_forever()
I then have a thread running on while not q.empty(): which parses the data by the other delimiter "~~~*~~~"
So this works for a while. An example of the kind of data I'm sending:
2016-02-23 18:01:24.140000~~~*~~~Snowboarding~~~*~~~Blue Hills~~~*~~~Powder 42
~~~*~~~Board Rental~~~*~~~15.0~~~*~~~1~~~*~~~http://bigshoes.com
~~~*~~~No Wax~~~*~~~50.00~~~*~~~No Ramps~~~*~~~2016-02-23 19:45:00.000000~~~*~~~-15
But things started to break. So I took some control data and sent it in a loop. Would work for a while then results started winding up in the wrong place. And this turned up in my queue:
2016-02-23 18:01:24.140000~~~*~~~Snowboarding~~~*~~~Blue Hills~~~*~~~Powder 42
~~~*~~~Board Rental~~~*~~~15.0~~~*~~~1~~~*~~~http://bigshoes.com
~~~*~~~No Wax~~~*~~~50.00~~~*~~~No Ramps~~~*~~~2016-02-23 19:45:00.000000~~~*~
Cutting out the last "~~-15".
So the exact same data works then later doesn't. That suggests some kind of overflow to me.
The client connects like this:
class Connect(object):
def connect(self):
host = socket.gethostname() # Get local machine name
#host = "127.0.0.1"
port = 500 # Reserve a port for your service.
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#print('connecting to host')
sock.connect((host, port))
return sock
def send(self, command):
sock = self.connect()
#recv_data = ""
#data = True
#print('sending: ' + command)
sock.sendall(command)
sock.close()
return
It doesn't wait for a response because I don't want it hanging around waiting for one. But it closes the socket and (as far as I understand) I don't need to flush the socket buffer or anything it should just be clearing itself when the connection closes.
Would really appreciate any help on this one. It's driving me a little spare at this point.
Updates:
I'm running this on both my local machine and a pretty beefy server and I'd be pushed to believe it's a hardware issue. The server/client both run locally and sockets are used as a way for them to communicate so I don't believe latency would be the cause.
I've been reading into the issues with TCP communication. An area where I feel I'll quickly be out of my depth but I'm starting to wonder if it's not an overflow but just some king of congestion.
If sendall on the client does not ensure everything is sent maybe some kind of timer/check on the server side to make sure nothing more is coming.
The basic issue is that your:
data = self.request.recv(163840000)
line is not guaranteed to receive all the data at once (regardless of how big you make the buffer).
In order to function properly, you have to handle the case where you don't get all the data at once (you need to track where you are, and append to it). See the relevant example in the Python docs on using a socket:
Now we come to the major stumbling block of sockets - send and recv operate on the network buffers. They do not necessarily handle all the bytes you hand them (or expect from them), because their major focus is handling the network buffers. In general, they return when the associated network buffers have been filled (send) or emptied (recv). They then tell you how many bytes they handled. It is your responsibility to call them again until your message has been completely dealt with.
As mentioned, you are not receiving the full message even though you have a large buffer size. You need to keep receiving until you get zero bytes. You can write your own generator that takes the request object and yields the parts. The nice side is that you can start processing messages while some are still coming in
def recvblocks(request):
buf = ''
while 1:
newdata = request.recv(10000)
if not newdata:
if buf:
yield buf
return
buf += newdata
parts = buf.split('*-New*Data-*')
buf = parts.pop()
for part in parts:
yield part
But you need a fix on your client also. You need to shutdown the socket before close to really close the TCP connection
sock.sendall(command)
sock.shutdown(request.SHUT_RDWR)
sock.close()
Background: So we were provided this script in class with the objective of opening random unprivileged ports on our Ubuntu VMs. He gave us two TCP examples and asked us to open two more additional TCP ports as well as two UDP ports. We were to accomplish this using the socket library and the Python programming language.
So I initially focused on the problem that he gave us. Using the python terminal this was the final script before I initially executed it knowing that the general concepts would open the ports for a connection on the Linux guest:
#!/usr/bin/env python
import signal
import socket
import sys
import time
import os
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s3 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s4 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s5 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s6 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def tcp_server() :
TCP_IP = '127.0.0.1'
s1.bind((TCP_IP, 6005))
s2.bind((TCP_IP, 1123))
s3.bind((TCP_IP, 6009))
s4.bind((TCP_IP, 1124))
s5.bind((TCP_IP, 6006))
s6.bind((TCP_IP, 6007))
s1.listen(1)
s2.listen(2)
s3.listen(3)
s4.listen(4)
tcp_server()
def SigAlarmHandler(signal, frame) :
print("Received alarm TCP server is shutting down")
sys.exit(0)
signal.signal(signal.SIGALRM, SigAlarmHandler)
signal.alarm(int(sys.argv[1]))
while True :
pass
When I execute the script on the Ubuntu VM I receive the following error message:
Traceback (most recent call last):
signal.alarm(int(sys.argv[1]))
IndexError: list index out of range
So I dug and I found these two little nuggets of information.
signal.alarm Python Docs:
https://docs.python.org/2/library/signal.html
Unix man page alarm(2)
http://unixhelp.ed.ac.uk/CGI/man-cgi?alarm+2
Looking at the man page for the alarm it seems that it is expecting an int type so I am not confident an explicit data conversion is necessary. Although I'm also not confident in the total direction of the script. The professor just gave it to us for bonus. He said he would look at it, but I'm not sure when he will get back to me.
I'm thinking that bit of code is setup that if one of the ports opened is probed the script will terminate. Looking at the man page it seems that if an int greater than 0 is returned the alarm will generate. Triggering the termination of the script. Although with an IndexError and not knowing what index it is referring to I'm unsure of where to narrow in on to resolve the issue.
The most likely explanation is that you are not passing any command line arguments to your script, and that it's sys.argv[1] that is raising the IndexError. Nothing to do with signals or sockets.
Call your script using ./ScriptName.py 5 and it should work, the alarm will fire after 5 seconds, and your server should exit.
References in case you're not familiar with sys.argv:
https://docs.python.org/2/library/sys.html#sys.argv
http://www.pythonforbeginners.com/system/python-sys-argv
User parses number of remote machines as a argument(python scriptName 3). During the execution script needs to connect and send data to this machines(in this case to 3 machines) in random order.
My code right now:
def createSocket(ip):
s = socket.socket()
s.connect((ip, 55555))
def sendData(data):
s.send(data)
def closeSocket():
s.close()
createSocket(ip)
sendData(data)
closeSocket()
So I'm using one socket and re-connect each time I need to connect to other machine. Because of that script transmits data really slowly.
Can I somehow assign required number of sockets during execution and use them? Or maybe there is a better way of keeping connection to all machines?
Don't create a single global socket, instead keep a list of sockets. Don't close your sockets after each use, and then reopen them: just keep them open.
eg.
def createSocket(ip): # return the new socket object
s = socket.socket()
s.connect((ip, 55555))
return s
addresses=[ip, ip2, ip3, ...]
sockets=[createSocket(addr) for addr in addresses]
sock = chooseSocket(sockets) # pick one (somehow)
sock.send(data) # use the selected socket
Okay, so in some experimentation with sockets and networking, I've set up a very basic chat client/server that runs on Unix flawlessly. Now I'm hitting some errors in the translation to win32. In preface, I understand that select.select() on Windows won't accept socket objects and have (I think) compensated coherently by not passing it the socket object, but the socket number. However, the script still hangs on the select.select() function and I have no idea why. The script only hangs until the server receives a message, after which it allows the client to send messages, however the client can't receive messages from the server, no matter what. I'm trying to troubleshoot these two bugs as best as I can, but my research has turned up dry. Here's the problem code, thanks in advance.
while True:
socket_list.append(s)
read_sockets, write_sockets, error_sockets = select.select(socket_list, [], [], 20)
if not (read_sockets or write_sockets or error_sockets):
if afk == False:
s.send('[Status]: '+str(_user)+' has gone afk.\n')
sys.stdout.write('\n[+]: You have gone afk.\n')
afk = True
prompt()
for sock in read_sockets:
print ('Starting for sock in read_sockets') #DEBUG#
if sock == s:
print ('Getting here.') #DEBUG#
data = sock.recv(4096)
if not data:
sys.stdout.write('[!]: Disconnected from chat server by server.\n'+W)
choice = raw_input('[*]: Press Enter to continue.')
_logic()
else:
sys.stdout.write(data)
else:
# Rest of the Program (Runs correctly) #
It sounds like you forgot to set the sockets non-blocking. Like pretty much all status reporting functions, select does not make future guarantees. You also need to handle the case where read returns a "would block" indication. You can't rely on select to predict the results of future read operations.