<p>You need to send a <code>version</code> message (and receiving the correspondant <code>verack</code>) before sending anything else. Here is a quickly patched version of your script which handles the version message:</p>



<pre><code>import hashlib
import random
import socket
import time
import urllib.request

PEER_IP = "127.0.0.1"
PEER_PORT = 8333

nonce = (random.getrandbits(64)).to_bytes(8, byteorder="little", signed=False)

magic_number = bytes.fromhex("f9beb4d9")
command_name = bytes.fromhex("ping".encode("utf-8").hex() + ("00")*8)
payload_size = (int(len(nonce))).to_bytes(4, byteorder="little", signed=False)
checksum = hashlib.sha256(hashlib.sha256(nonce).digest()).digest()[:4]

pong_msg = (
    magic_number
    + command_name
    + payload_size
    + checksum
    + nonce
)

# Magic bytes, as usual
magic = bytes.fromhex('f9beb4d9')
# Version number (PROTOCOL_VERSION in core)
version = int(70015).to_bytes(4, 'little')
# Random services, we don't care
services = int(1).to_bytes(8, 'little')
timestamp = int(time.time()).to_bytes(8, 'little')
myip_str = urllib.request.urlopen('https://api.ipify.org').read().decode()
myip = socket.inet_aton(myip_str)
nodeip = socket.inet_aton(PEER_IP)
# https://en.bitcoin.it/wiki/Protocol_documentation#Network_address
addr_recv = services + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff'
addr_recv += nodeip + int(8333).to_bytes(2, 'big')
addr_from = services + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff'
addr_from += myip + int(8333).to_bytes(2, 'big')
nonce = 0x00.to_bytes(8, 'little')
# You can replace this with something more fun
user_agent = 0x00.to_bytes(1, 'big')
# Let's say zero, once again we don't care for this example
start_height = 0x00.to_bytes(4, 'little')
# The message content, which we'll compute the checksum from
payload = version + services + timestamp + addr_recv + addr_from + nonce
payload += user_agent + start_height
checksum = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4]
payload_length = len(payload)
# The command type, as NULL padded ascii
version_message = magic + 'version'.encode('ascii') + b'\x00\x00\x00\x00\x00'
version_message += payload_length.to_bytes(4, 'little') + checksum + payload

sock = socket.socket()
sock.connect((PEER_IP, PEER_PORT))
print('Sending version message..',)
sock.send(version_message)
print('Received verack: {}'.format(sock.recv(24)), end='\n\n')
print('Sending ping..')
sock.send(pong_msg)
print('Received pong: {}'.format(sock.recv(1024)))
</code></pre>

<p>And here is a sample output of my node:</p>

<pre><code>Sending version message..
Received verack: b'\xf9\xbe\xb4\xd9version\x00\x00\x00\x00\x00h\x00\x00\x00n\x8a\xbe\xc7'

Sending ping..
Received pong: b'\x7f\x11\x01\x00\r\x04\x00\x00\x00\x00\x00\x00\x86\xc5\x08^\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7\xa0vQ\x16V\xb1\xab\x12/Satoshi:0.19.0.1/\x14P\t\x00\x01\xf9\xbe\xb4\xd9verack\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\xf6\xe0\xe2'
</code></pre>

<p>Here is the <a href="https://en.bitcoin.it/wiki/Protocol_documentation#version" rel="nofollow noreferrer">protocol documentation</a>, on which you can rely for implementing protocol messages.</p>

CC BY-SA 4.0
2019-12-30T01:01:50.480Z
Great, thanks so much for your help. Much appreciated.
samdpedraza
CC BY-SA 4.0
2019-12-29T15:27:49.033Z
2019-12-29T15:27:49.033Z
Antoine Poinsot
<p>I am struggling greatly trying to figure out how to send a basic "PING" message, and receive back a "PONG" response.</p>



<pre><code>import random
import hashlib
import socket
PEER_IP = "35.187.200.6"
PEER_PORT = 8333

nonce = (random.getrandbits(64)).to_bytes(8, byteorder="little", signed=False)

magic_number = bytes.fromhex("f9beb4d9")
command_name = bytes.fromhex("ping".encode("utf-8").hex() + ("00")*8)
payload_size = (int(len(nonce))).to_bytes(4, byteorder="little", signed=False)
checksum = hashlib.sha256(hashlib.sha256(nonce).digest()).digest()[:4]

final_msg = (
    magic_number
    + command_name
    + payload_size
    + checksum
    + nonce
)

sock = socket.socket()
sock.connect((PEER_IP, PEER_PORT))
sock.send(final_msg)
pong = sock.recv(1024)
print(pong)

</code></pre>

<p>I am following this <a href="https://www.youtube.com/watch?v=4TBAjTPvRxE&amp;list=PLQ56Yiu6lEayrOrjxefwkxKakZgMNIzL0&amp;index=5" rel="nofollow noreferrer">YouTube</a> tutorial, and added the socket layer myself.</p>

<p>The only response I get is</p>

<pre><code>b''
</code></pre>

<p>Any insight into what I am doing wrong here, would be greatly appreciated.</p>

<p>Thanks</p>

CC BY-SA 4.0
2019-12-28T17:03:48.400Z
I believe you need to negotiate a `version` message before any other communication can occur. Also, receiving a zero length array on `recv` means the socket has been disconnected.
Mark H
<client><network><protocol><python>
How to Construct a Ping Message
samdpedraza
# How to Construct a Ping Message

(Asked by: username_0 on 2019-12-28)

I am struggling greatly trying to figure out how to send a basic "PING" message, and receive back a "PONG" response.
import random
import hashlib
import socket
PEER_IP = "35.187.200.6"
PEER_PORT = 8333

nonce = (random.getrandbits(64)).to_bytes(8, byteorder="little", signed=False)

magic_number = bytes.fromhex("f9beb4d9")
command_name = bytes.fromhex("ping".encode("utf-8").hex() + ("00")*8)
payload_size = (int(len(nonce))).to_bytes(4, byteorder="little", signed=False)
checksum = hashlib.sha256(hashlib.sha256(nonce).digest()).digest()[:4]

final_msg = (
    magic_number
    + command_name
    + payload_size
    + checksum
    + nonce
)

sock = socket.socket()
sock.connect((PEER_IP, PEER_PORT))
sock.send(final_msg)
pong = sock.recv(1024)
print(pong)


I am following this YouTube tutorial, and added the socket layer myself.
The only response I get is
b''

Any insight into what I am doing wrong here, would be greatly appreciated.
Thanks

**Tags:** client, network, protocol, python

> **Comments:**
> **username_1**: I believe you need to negotiate a `version` message before any other communication can occur. Also, receiving a zero length array on `recv` means the socket has been disconnected.  

---

## 1 answers

### Answer by username_2 on 2019-12-29. Score: 2 | Accepted answer

You need to send a version message (and receiving the correspondant verack) before sending anything else. Here is a quickly patched version of your script which handles the version message:
import hashlib
import random
import socket
import time
import urllib.request

PEER_IP = "127.0.0.1"
PEER_PORT = 8333

nonce = (random.getrandbits(64)).to_bytes(8, byteorder="little", signed=False)

magic_number = bytes.fromhex("f9beb4d9")
command_name = bytes.fromhex("ping".encode("utf-8").hex() + ("00")*8)
payload_size = (int(len(nonce))).to_bytes(4, byteorder="little", signed=False)
checksum = hashlib.sha256(hashlib.sha256(nonce).digest()).digest()[:4]

pong_msg = (
    magic_number
    + command_name
    + payload_size
    + checksum
    + nonce
)

# Magic bytes, as usual
magic = bytes.fromhex('f9beb4d9')
# Version number (PROTOCOL_VERSION in core)
version = int(70015).to_bytes(4, 'little')
# Random services, we don't care
services = int(1).to_bytes(8, 'little')
timestamp = int(time.time()).to_bytes(8, 'little')
myip_str = urllib.request.urlopen('https://api.ipify.org').read().decode()
myip = socket.inet_aton(myip_str)
nodeip = socket.inet_aton(PEER_IP)
# https://en.bitcoin.it/wiki/Protocol_documentation#Network_address
addr_recv = services + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff'
addr_recv += nodeip + int(8333).to_bytes(2, 'big')
addr_from = services + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff'
addr_from += myip + int(8333).to_bytes(2, 'big')
nonce = 0x00.to_bytes(8, 'little')
# You can replace this with something more fun
user_agent = 0x00.to_bytes(1, 'big')
# Let's say zero, once again we don't care for this example
start_height = 0x00.to_bytes(4, 'little')
# The message content, which we'll compute the checksum from
payload = version + services + timestamp + addr_recv + addr_from + nonce
payload += user_agent + start_height
checksum = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4]
payload_length = len(payload)
# The command type, as NULL padded ascii
version_message = magic + 'version'.encode('ascii') + b'\x00\x00\x00\x00\x00'
version_message += payload_length.to_bytes(4, 'little') + checksum + payload

sock = socket.socket()
sock.connect((PEER_IP, PEER_PORT))
print('Sending version message..',)
sock.send(version_message)
print('Received verack: {}'.format(sock.recv(24)), end='\n\n')
print('Sending ping..')
sock.send(pong_msg)
print('Received pong: {}'.format(sock.recv(1024)))

And here is a sample output of my node:
Sending version message..
Received verack: b'\xf9\xbe\xb4\xd9version\x00\x00\x00\x00\x00h\x00\x00\x00n\x8a\xbe\xc7'

Sending ping..
Received pong: b'\x7f\x11\x01\x00\r\x04\x00\x00\x00\x00\x00\x00\x86\xc5\x08^\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7\xa0vQ\x16V\xb1\xab\x12/Satoshi:0.19.0.1/\x14P\t\x00\x01\xf9\xbe\xb4\xd9verack\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\xf6\xe0\xe2'

Here is the protocol documentation, on which you can rely for implementing protocol messages.

> **Comments:**
> **username_0**: Great, thanks so much for your help. Much appreciated.  

---

