I'm sending data via sockets between godot and python like this:
godot:
var socket = PacketPeerUDP.new()
socket.set_dest_address("127.0.0.1", 6000)
var data={...}
socket.put_packet(JSON.print(data).to_ascii())
python server:
s= socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.bind(("127.0.0.1", 6000))
while True:
data = s.recvfrom(1024)
but the problem is even when the python server is not running the godot code sends the data instead of giving an error that the server is not available
I even tried var err=socket.set_dest_address("127.0.0.1", 6000) hopin this would print out the error
but it always prints 0 whether the python server is running or not
so how do I check if the server is available or not?
This is UDP we are talking about. So there isn't really a session or connection established. Also there isn't really an acknowledged package. So at the end the only solution is to implement your own reliability protocol on top of it (e.g. have the server respond and the client wait for the response). Try searching dor UDP reliability on the gamedev site.
The return values for set_dest_address are ERR_CANT_RESOLVE (the IP is not valid) or OK.
The returns values of put_packet. It can return ERR_BUSY (send buffers are full), FAILED (the socket is otherwise in use) or OK.
Related
I am learning Python; specifically, I'm learning about network architecture and HTTP requests. The course example below demonstrates how to write a simple web browser.
import socket
mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysock.connect(('data.pr4e.org', 80))
cmd = 'GET http://data.pr4e.org/romeo.txt HTTP/1.0\r\n\r\n'.encode()
mysock.send(cmd)
while True:
data = mysock.recv(512)
if (len(data) < 1):
break
print(data.decode(),end='')
mysock.close()
I understand that the .connect() function starts the two-way communication, effectively "opening the tunnel". The syntax is socketname.connect(('address'),port)
However, I am wondering if there is a difference between that function and the CONNECT method described here. That syntax is:
CONNECT serverurl: port
Specifically, when is it appropriate to use one or the other?
The .connect() function is connecting the TCP socket to the remote server, which allows data to be sent to and received from the server. In your case you're using the TCP socket to send HTTP commands, and receive corresponding HTTP responses.
The HTTP CONNECT method is something completely different. It's a type of HTTP command, which include GET (the one you're using), HEAD, POST, PUT, etc that can be sent over your connected socket. CONNECT is related to HTTP tunneling (i.e. having the web server proxy your requests to another server).
When you send a CONNECT command, you're basically instructing the server to forward future HTTP commands to a different HTTP server. So it is sort of like being 'connected' to that other server in a way.
I'm trying to retrieve data from a PLC (AutomationDirect P2000). I have set up the PLC as the server with their software program (I can also connect to it with their software via Ethernet and use Wireshark to see it is in fact sending UDP packets to my machine at roughly every 200ms). I am trying to set up a very simple Python script to retrieve said data, without bothering to encode it or do anything with it, but my program hangs at the socket.recv(). Whenever I try to run it "Got here" will be printed, but "Now here" will not. From what I've read the fact that it hangs means there's no data to be received, but from my (limited) understanding of what I see on Wireshark this is not the case. I am pretty new to all of this and would appreciate any help.
I have tried using socket.recvfrom(), which produces the same result. I've also tried using socket.bind() instead of socket.connect() but I get a "The requested address is not valid in its context" exception. Additionally, I've tried playing around with various IPs and ports. For example, I've tried using IP = '' instead of the actual IP, and I've tried the source/destination information from Wireshark as what I try to bind or connect to, but nothing thus far has worked.
import socket
IP = '192.168.3.1'
PORT = 9999
BUFFER_SIZE = 4096
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((IP, PORT))
while True:
print("Got here")
data = s.recv(BUFFER_SIZE)
print("Now here")
print(f"Received {data}")
I am expecting to get a print out of the packet in byte format, but instead the program is hanging. If I try socket.bind() instead of socket.connect() I get an error message reading "...line 8, in
s.bind((IP, PORT))
OSError: [WinError 10049] The requested address is not valid in its context"
you can't use bind like this, because the ip address does not belong to your PC.
when you connect to the server, it (the server) doesn't send anything, but you try to get data from the server, so the socket awaits until it gets data, and only then it will continue the execution (this is called a blocking function, since it blocks the execution until it finishes).
The issue was with how I set up the PLC as the server. The UDP data I was seeing on port 9999 wasn't the communications I was thinking it was, and was only the inherent communication between the PLC and the network via its proprietary program. For anyone curious, I am using a P2000 PLC from AutomationDirect and initially I set it up as an EtherNet/IP Adapter following one of their videos, but I had to use the Custom Protocol over Ethernet functionality provided in the "Communications" section.
I am trying to implement a python traceroute that sends UDP messages and receives the ICMP responses via raw sockets. I've run into an issue where the ICMP packets seem to avoid capture at all cost. The ICMP responses show up in wireshark as exactly what I'd expect, but the socket never receives any data to read. Another complication is that I am running the code on VirtualBox running Ubuntu, as the sendto() would not get the packets on the wire in Windows 7. (I'm running wireshark in windows to capture the packets). The strange thing is that wireshark will capture the ICMP messages when I run the python script from the virtual machine. However, when I try to run the script on windows, the ICMP messages don't show up in wireshark. (The UDP packets have magically started working on windows)
I've played around with all sorts of different versions of setting up the socket from online examples, and played around with using bind() and not using it, but no configuration seems to produce a socket that reads. It will just time out waiting to read the ICMP message.
It should also be noted that if I try to read my udp sending socket, it successfully reads the udp packets. As soon as I set IPPROTO_ICMP the read times out.
receive_response method:
def receive_response(rec_socket, packetid, tsend, timeout):
remain = timeout
print packetid
while remain > 0:
ready = select.select([rec_socket], [], [], remain)
if ready[0] == []:
return
print 'got something'
setting up the socket:
rec_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, ICMP_CODE)
rec_socket.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1)
rec_socket.bind(("",0)) #played with using this statement and skipping it
call to receive is simply:
reached = receive_response(rec_socket, packetid, time.time(), timeout)
It looks like the problem is VirtualBox will default to using NAT to connect to the network. This means that the virtual machine won't receive the ICMP messages by virtue of them being ICMP messages. It seems like the solution to this is to configure VirtualBox networking to use "Bridged networking" mode. Unfortunately I cannot confirm this as I can't set up the virtual machine on my university's network within bridged mode. As for the reason they didn't work in windows, it must be related to windows' lack of support for raw sockets.
I currently have a client/server pair coded against PyBlueZ. Right now the server can connect to sequential clients - it will work until its completed with a client, then it will begin listening for another client.
However, what I really want is to run client communication in separate threads so I have multiple clients at the same time. When I try a 2nd client connection, however, PyBlueZ advertises the same port that the first client is currently using. I am setting up connections like this:
self.port = bluetooth.PORT_ANY
print "Accepting clients..."
self.server_sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
self.server_sock.bind(("",self.port))
self.server_sock.listen(5)
print "listening on port %d" % self.port
bluetooth.advertise_service( self.server_sock, MY_SERVICE, MY_UUID )
client_sock,address = self.server_sock.accept()
print "Accepted connection from ",address
commThread = ServerThread(client_sock, self.bn_id, self.bn_name, self.bn_thumbnail)
Again, this code works fine for sequential connections, but when I try it in parallel my client gets a "busy" response from the server's bluetooth system. On the client side I output the port its trying to connect to and it always shows port "1".
Is there a limitation in PyBlueZ which only allows for a single connection? Or am I doing something wrong here for parallel connections?
I think your problem has nothing to do with the Bluetooth client part of the code.
You were right to show the Bluetooth server code. What you should try to change:
Only advertise a service once, and once only (No need to advertise it for every server thread)
Allocate a different server channel for each thread. (On RFCOMM connection, there usually is a RFCOMM manager which allocates a new server channel per each socket. I think in your case you might have to do that manually.) Change this code
self.port = bluetooth.PORT_ANY
Try channels 1, 2 and so on and see if it works! Then all you have to do is keep track of the allocated channels.
Please let me know if it worked!
I am writing 2 small programs (a server and a client) and whenever I run both, and have the client connect to the server, the server output says that I am connected on a port of which I didn't bind in the code. I binded both the server and the client socket to the localhost and port 8000, but every time the server is connected to by the client, it says that the client is connected on port 52304 or some other number larger than 50000, shouldn't it at least be a constant port number even if it isn't the one I bound it to? Also, I know, that if I run the server program more than once in the same terminal, even if I exited the program, the port is still taken, so I usually run the server, quit, then exit the terminal, which usually solves that problem. That is another note I should make, when I do run the server program the second time in the same terminal, it recognizes I am trying to bind to port 8000 and the program wont run, then when it does it chooses some random port.
Here is my server code:
import socket
import os
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind('', 8000)
s.listen(5)
while 1:
client,addr = s.accept()
print "Accepted a connection from: ", addr
data = client.recv(1024)
client.send("You said: " + data)
The port number it's reporting is the one the client connected from. And it will be a random port number. If (as your question seems to imply) you have a bind call in the client that looks just like the one in the server, then I'm surprised it's succeeding since the server has already bound itself to that port and only one thing can be bound to a given port at a time.
Please post your client code. Contrary to what your question implies, I don't think that you are binding to a port on the client side. I'm betting you're just connecting. Now, that, generally speaking, is what you're supposed to be doing. So the fact you're confused by the results just means that you don't really understand what's happening exactly. The results you're seeing are perfectly expected and normal.
Here is an explanation of what's going on:
A TCP connection is uniquely identified (globally unique, as in no other TCP connections in the entire world will have the same identifier (though this isn't really exactly true with NAT and private IP ranges)) by these 4 pieces of information:
client ip
client port #
server ip
server port #
When your server is reporting a connection, it's printing out the first two values because they are what is returned by the accept call. When you are doing a bind call in the server, you are specifying values 3 and 4. The OS generally picks values 1 and 2 for the client automatically when it does a connect call.
A client normally does not bind to a port (though it can). It normally lets the OS pick a port for it. The client's OS will pick a port number from a list of unused port numbers. In your connect call on the client side, you are giving values 3 and 4 (the values specified in the bind call on the server side). The OS should automatically assign your client values 1 and 2 for you.
Think about it like the sender and recipient address on an envelope. The accept call on the server side reports the sender address because presumably the server already knows its own address. The client is most concerned with the recipient address (the address of the server) and lets a clerk (the OS) just paste on a return address,
The port and socket that the server listens on is not the same socket that is used once the connection is established. The accept call creates a new socket when a client connects for sending and receiving data. Otherwise if it used the same socket...then no other clients would be able to connect.
You also need to properly close your socket so it does not hang around after your program terminates.
You can never bind the same port to more then one program, the port the server gives you is the port the client wants you to send the data over. I think its to avoid connection collisions.
So you don't have to worry about the ports if the connection is establish.
But if you want the server to be able to receive more the one connection take a look at this:
Multiple simultaneous network connections - Telnet server, Python