I have a code which consists of something similar to this, which works in Linux. Now i want to port this to Windows. I know that Windows uses winsock for socket programming but is it possible to implement this python module "socket" in windows as well?
```
import socket
host = self.config.get_config('BASE_ADDRESS',BASE_ADDRESS_VAL)
port = self.config.get_config('BASE_PORT',BASE_PORT_VAL)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,socket.IPPROTO_UDP)
if sock is None:
print('could not open socket')
sys.exit(1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.append(sock)
self.log.info('Listening to %s:%s' % (host, port))
try:
sock.bind((host, int(port)))
except socket.error as msg:
print('Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1])
sys.exit()
#sock.bind(("10.0.0.1", ""))
while self.winParent.ongoing==True:
try:
r,w,e = select.select(self.sock, [], self.sock,self.timeout)
for sock in r:
data, addr = sock.recvfrom(556)
#something = sock.recvfrom(556)
#print(something[0].decode())
self.handle(sock, addr, data)
except (Exception, e):
import traceback
self.log.critical('%s\n%s' % (str(e), traceback.format_exc()))
time.sleep(1)
for sock in self.sock:
sock.close()
self.sock = []
My code gets stuck at "r,w,e = select.select(self.sock, [], self.sock,self.timeout)".
On investigating with Wireshark, I can see the following:
[1]: https://i.stack.imgur.com/zNxKH.png
I have the following points of doubt :
(1) Could this be a firewall issue? I have added python.exe to allow through Firewall in Windows Defender. Am I missing something basic?
(2) Should I have the winsock.dll installed separately?
The socket module works just fine on Windows and that's not the source of the problem here. As you've helpfully pointed out, it's select where your code gets stuck (the posix select() is the traditional Unix way of servicing sockets). It's supposed to get stuck, as it's sitting and waiting for incoming packets :) You are sending some packets to it, right?
Since you're expecting incoming UDP packets the Windows Firewall might need additional convincing to allow those. Double-check with a quick Google search.
Related
I would like to preface that I am new to networking and still working on my python skills so go easy on me.
I have started working on a network scanning project and have played with multiple protocols to try and find what works best for my purposes. SSDP seems to be the best for me thus I have been playing with a little universal plug and play script I found to try and test how things are working on my network.
import socket
import sys
dst = "239.255.255.250"
st = "upnp:rootdevice"
msg = [
'M-SEARCH * HTTP/1.1',
'Host:239.255.255.250:1900',
'Man:"ssdp:discover"',
'MX:1',
'ST:%s' % (st,),
'']
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.bind((socket.gethostbyname(socket.gethostname()), 0))
print(s.getsockname())
s.settimeout(60)
byte_data = '\r\n'.join(msg)
s.sendto(bytes(byte_data, 'utf-8'), (dst, 1900))
while True:
try:
data, addr = s.recvfrom(32*1024)
except socket.timeout:
print("timeout has occurred")
break
print (f"$ {addr}\n{data}")
s.close()
For some reason this always times out for me and never displays any data. After investigating using WireShark, I can see that my computer is sending out searches and devices are sending replies back to my computer. Does anyone know why this might be occurring (OS is windows 10). I will say I have increased the timeout numerous times to high amounts and still nothing is getting through.
As pointed out in the comments, there should be an extra blank line in the M-SEARCH request header, so.
import socket
import sys
dst = "239.255.255.250"
st = "upnp:rootdevice"
msg = [
'M-SEARCH * HTTP/1.1',
'Host:239.255.255.250:1900',
'Man:"ssdp:discover"',
'MX:1',
'ST:%s' % (st,),
'',
'']
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.bind((socket.gethostbyname(socket.gethostname()), 0))
print(s.getsockname())
s.settimeout(2)
byte_data = '\r\n'.join(msg)
s.sendto(bytes(byte_data, 'utf-8'), (dst, 1900))
while True:
try:
data, addr = s.recvfrom(32 * 1024)
except socket.timeout:
print("timeout has occurred")
break
print(f"$ {addr}\n{data}")
s.close()
Now it works. Also, with the SSDP MX header set to 1 it is pointless setting timeout to 60 - any device responding to the request MUST reply within MX seconds or not at all.
As it is, this should work fine on a system with a single network interface. But on a multi-homed system you will need to send the request on each interface by binding a socket to that interface, otherwise some UPNP devices might not be reachable.
My first question here, please be gentle :) I'm trying to setup a basic Python (2.7) TCP socket server that is multithreaded (I haven't got to the multithreaded part yet), and a client.
Here is the server:
# Basic TCP socket server
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = ''
port = 8888
s.bind((host, port))
s.listen(5)
while True:
c, addr = s.accept()
print("Connected to %s" % addr)
c.send("Hello socket")
c.close()
And here is the client:
# Basic TCP socket client
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = '127.0.0.1'
port = 8888
s.connect((host, port))
print s.recv(1024)
s.close()
When I run the server it seems to execute without errors, but when I run the client to connect, I don't see the message that should be printed out to my terminal window where server is running. Here is the error (as #Rawing pointed out):
Traceback (most recent call last): File "server.py", line 19, in
print("Connected to %s" % addr) TypeError: not all arguments converted during string formatting
As far as making the server multithreaded, I need to read up on that but any suggestions are welcome.
Thank You.
You have two problems in your code
Your use of the string-formatting operator % is incorrect in your server program. If you pass a tuple to % (and addr is a tuple), then each item in the tuple must match one formatting directive. This is why your server program is failing.
print("Connected to %s" % str(addr))
In both programs, you mention, but do not invoke, socket.close. Try these in the appropriate locations:
s.close()
c.close()
A simple implementation of a TCP server in python 3 (If you are willing to use it instead of 2.7)
Server:
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.rfile.readline() # Receive data from client
self.wfile.write(new_data) # Send data to client
if __name__ == "__main__":
with socketserver.UDPServer((HOST, PORT), MyUDPHandler) as server:
server.serve_forever()
Client:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((HOST, PORT)) # Connect
sock.sendall(bytes(data + "\n", "utf-8")) # Send data
received = str(sock.recv(1024), "utf-8") # Receive data synchronically
bind the server to an ip, eg: host='127.0.0.1, and it should work.
Update: I'm totally wrong. I fixed a few things in your scripts and assumed that was the issue, but it's not - as the reply below states, binding to ('', ) is perfectly valid.
Looks like your socket code is perfectly good, but falls over the print statement. I fixed it with print("Connected to {}".format(addr))
I am programming a client-server instant message program. I created a similar program in Python 2, and am trying to program it in Python 3. The problem is when the server takes the message and tries to send it to the other client, it gives me "[Errno 32] Broken Pipe" and exits.
I have done some research, and found that this occurs when the client disconnects, so I did some more testing but could not find when the client disconnects. (I am using Ubuntu 14.04 and Python 3.4)
Here is the server code:
import socket, select, sys
def broadcast(sock, messaged):
for socket in connection_list:
if socket != s and socket != sock:
# Here is where it gives me the broken pipe error
try:
s.send(messaged.encode("utf-8"))
except BrokenPipeError as e:
print(e)
sys.exit()
connection_list = []
host = ''
port = 5558
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,port))
s.listen(5)
connection_list.append(s)
read_sockets,write_sockets,error_sockets = select.select(connection_list,[],[])
while True:
for sock in read_sockets:
if sock == s:
conn, addr = s.accept()
connection_list.append(conn)
client = "Client (%s,%s) connected" % addr
print(client)
broadcast(sock,client)
else:
try:
data = sock.recv(2048)
decodeddata = data.decode("utf-8")
if data:
broadcast(sock, decodeddata)
except:
offline = "Client " + addr + "is offline"
broadcast(sock, offline)
print(offline)
connection_list.remove(sock)
sock.close()
continue
And the client code:
import socket, select, string, sys, time
def prompt(data) :
print("<You> " + data)
def Person(data) :
print("<Receiver> " + data)
if __name__ == "__main__":
host = "localhost"
port = 5558
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
try:
s.connect((host,port))
except:
print('Unable to connect')
sys.exit()
print('Connected.')
socket_list = [s]
read_sockets,write_sockets,error_sockets = select.select(socket_list,[],[])
while 1:
for sock in read_sockets:
if sock == s:
try:
time.sleep(1)
data = sock.recv(1024)
Person(data.decode("utf-8"))
except:
msg = input("Send a message: ")
try:
s.send(str.encode(msg))
except:
print("Server is offline")
sys.exit()
else:
print("Server is offline")
sys.exit()
There are two problems that you have to fix to make this work.
First, on both the client side and the server side, you have to put the select inside the loop, not outside. Otherwise, if there was something to read before you got to the loop, you'll recv over and over, and if there wasn't, you'll never recv. Once you fix this, you can get rid of the time.sleep(1). (You should never need a sleep to solve a problem like this; at best it masks the problem, and usually introduces new ones.)
Meanwhile, on the server side, inside broadcast, you're doing s.send. But s is your listener socket, not a connected client socket. You want socket.send here, because socket is each socket in connection_list.
There are a number of unrelated problems in your code as well. For example:
I'm not sure what the except: in the client is supposed to be catching. What it mainly seems to catch is that, about 50% of the time, hitting ^C to end the program triggers the send prompt. But of course, like any bare except:, it also masks any other problems with your code.
There's no way to send any data back and forth other than the "connected" message except for that except: clause.
addr is a tuple of host and port, so when someone goes offline, the server raises a TypeError from trying to format the offline message.
addr is always the last client who connected, not the one who's disconnecting.
You're not setting your sockets to nonblocking mode.
You're not checking for EOF on the recv. This means that you don't actually detect that a client has gone offline until you get an error. Which normally happens only after you try to send them a message (e.g., because someone else has connected or disconnected).
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.
I have the following scripts:
import socket
import sys
import traceback
msg = socket.gethostbyname(socket.gethostname())
dest = ('<broadcast>',10100)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(msg, dest)
print "Sent."
while 1:
(buf,address)=s.recvfrom(10100)
if not len(buf):
break
print "Received from %s: %s" %(address, buf)
And then:
import socket
import traceback
import os
host = ''
port = 10100
sx = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sx.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sx.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sx.bind((host,port))
while 1:
try:
message, address = sx.recvfrom(10104)
print "Got data from", address
sx.sendto("ola",address)
except (KeyboardInterrupt, SystemExit):
raise
except:
traceback.print_exc()
I'm having some trouble having both of them on the same script.
I just wanted to learn more about sockets, etc, this is nothing in particular.
My idea was to have just one script in each machine (Raspberry Pi), and whenever they're on the same network, one will know about the presence of the other.
Hope I had explained right.
You can send and receive on the same socket, you don't need the second one. Use something like select with a timeout to wait for others to contact you, broadcast on the timeout expiring to let others know about yourself (you might want to keep something like time left to next broadcast, so you don't lose broadcasting schedule on receipt of a datagram).
Thanks for all the help.
I've found these two links.
The first one is really great, simple and is working like needed. May help someone else:
http://www.cs.bilgi.edu.tr/~mgencer/Ders%20Malzemeleri/IThingTaggedFile/p2p.py
https://github.com/zetaron/python-udp-p2p