Jun 15
Digg
Stumbleupon
Technorati
Delicious

Network programming for PyS60 (XII)

Until now we have used only TCP in our examples due to its reliability. In fact, UDP could be used when reliability is not an issue or when you implement it in the application layer. However, UDP is your only solution when talking about multicast and broadcast. In this post we will explore the multicast topic from the programmers perspective (see the related theory in our last post). At this moment, I think it may be more interesting than generic UDP sockets issues (I will explore it later).

Consider the multicast address 224.202.20.30. The following PyS60 program will send a hello world message at each two seconds to this address and in the screenshot you can see the multicast frame, addressed to  MAC 01:00:5e:4a:14:1e. Since we are dealing with UDP, the socket is created using SOCK_DGRAM and not SOCK_STREAM.

# Marcelo Barros de Almeida
# marcelobarrosalmeida@gmail.com
 
import time
try:
    from btsocket import *
except:
    from socket import *
 
from appuifw import note, popup_menu
 
def sel_access_point():
    aps = access_points()
    if not aps:
        return None
    ap_labels = map(lambda x: x['name'],aps)
    item = popup_menu(ap_labels, u"Access point:")
    if item is None:
        return None
    apo = access_point(aps[item]['iapid'])
    set_default_access_point(apo)
    return apo
 
GROUP = "224.202.20.30"
PORT = 54321
 
apo = sel_access_point()
if apo is not None:
    apo.start()
    sock = socket(AF_INET, SOCK_DGRAM)
    while True:
        n = sock.sendto('hello world',(GROUP,PORT))
        print "Message sent (%d bytes)" % n
        time.sleep(2)

Instead the known send() function, here it is used sendto(). sendto has an additional parameter, indicating the message destination in the format (address,port). This is necessary since we do not have a phase for connection establishment, with explicit call to connect(), as it is usual in TCP sockets. Thus, client UDP sockets just need to be created and explicitly addressed in sendto(). You can connect an UDP socket, for instance, and use send()/recv() primitives instead non-connected versions sendto()/recvfrom() if you want.

Multicasting from mobile.

For receiving multicast messages, first create the socket and bind it to the interface. After, it is necessary to join to the desired group, as discussed in our last post. This can be done using two calls to setsockopt() function. The first call enables multicast reception for the interface and the second one tell to the network card which IP we are waiting for. setsockoption has three parameters (there are many socket options and it is better to dedicate a post to the most important ones):

  • level:it is used to selected a group of options, like SOL_SOCKET for socket options and SOL_IP for options related to IP layer.
  • option name: the value of the option
  • option value: new value to the option

inet_aton() converts an IPv4 address to 32-bit packed binary format, as a string four characters (see Python docs).

The last step is to call recvfrom(). Again, recvfrom() is similar to recv() but it will return the address of the incoming package as well (remember: we are not connected).

Using Python 1.9.5 (socket module) it was only possible to send broadcast messages. For receiving, it is necessary to select the access point first but access point functions are only in btsocket and they do not affect socket module. Moreover, btsocket does not have the necessary socket options. So, I did the following PC code for receiving the first ten multicast messages:

import time
import sys
import socket
 
GROUP = "224.202.20.30"
PORT = 54321
 
def join_grp(sock,grp,itf):
    # enabling multicasting option for itf
    sock.setsockopt(socket.SOL_IP,
                    socket.IP_MULTICAST_IF,
                    socket.inet_aton(itf))
    # joing to multicast group grp in interface itf
    sock.setsockopt(socket.SOL_IP,
                    socket.IP_ADD_MEMBERSHIP,
                    socket.inet_aton(grp)+socket.inet_aton(itf))
 
def leave_grp(sock,grp):
    # removing
    sock.setsockopt(socket.SOL_IP,
                    socket.IP_DROP_MEMBERSHIP,
                    socket.inet_aton(grp)+socket.inet_aton('0.0.0.0'))
 
itf_addr = '10.0.0.101'
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock.bind((itf_addr,PORT))
join_grp(sock,GROUP,itf_addr)
 
n = 0
while True:
    (data,addr) = sock.recvfrom(1500)
    print "Received ",data,"from",addr
    n = n + 1
    if n > 10: break
 
leave_grp(sock,GROUP)

Receiving multicast

In time: I had a lot of problem during this test session. They are below, just for helping you.

  • Windows firewall enabled
  • Access point with MAC filter enabled
  • Wireshark only working in non-promiscuous mode for my Acer Aspire One
  • Missing socket options in PyS60 socket API
  • Python 1.9.5 seems with better network support than Python 1.4.5

Related posts:

  1. Network programming for PyS60 (XIII) In our last post we talked about multicast, a special...
  2. Network programming for PyS60 (XV) As discussed in post III, TCP sockets have flow...
  3. Network programming for PyS60 (XI) We have already talked about IP addressing in the post...
  4. Network programming for PyS60 (VII) Everything is about “protocols” in computer networks, doesn’t it ?...
  5. Network programming for PyS60 (IV) Network programming is innocuous if you don’t have at least...

Related posts brought to you by Yet Another Related Posts Plugin.


Author: Marcelo Barros

4 Comments

Vygandas
June 19, 2009

Hello, Marcello,

Your posts a really informative and nice.
I would like to discuss something about UDP. Because the protocol is not controlled, we face few problems, for example: we have an application in mobile phone, which is waiting for some data from server with real IP address. The problem is that we don’t have open ports in mobile phone while connecting through 3G or GPRS. I managed to use it by sending something from mobile phone first, and then using that connection with given random port in server. This way we need an open port in one side of connection. Maybe You have some suggestions about that.
Another problem in using UDP is that we have to manually control all traffic to UDP port. It is necessary to limit the traffic or there will be many lost packets.

Thanks for Your posts!

Marcelo Barros
June 19, 2009

Hello Vygandas, fine ?

> his way we need an open port in one side of connection

I think this is an operator issue. In Brazil, some operators provides real IPs and do not block incoming connections to your phone. I did a test here with TIM/Brazil and I could connect to the phone. But I know that we have some operators that block incoming connections and provide just IPs reserved for internal networking. In this case, you need to pay for some special services. Please, check this info with your mobile operator.

> Another problem in using UDP is that we have to manually control all traffic to UDP port.

UDP issues… Possible suggestions: increase receiver buffer according to the equation:

buffer_size = maximum_latency*average_rate

But it is necessary to use setsockopt (option SO_RCVBUF in SOL_SOCKET group). I need to check if this option is available for PyS60.

Vygandas
June 19, 2009

yeah, my project is fine, but it doesn’t work with 3g. Also my software should be more accurate and safer to use. As you know, it is in deep beta version right now :)

> you need to pay for some special services

maybe not… as i said it is possible to open a session if mobile sends some data to server, and server gets that data from mob_ip:rand_port, so we can use that session to send data from server to mobile…

> buffer_size = maximum_latency*average_rate

i used something similar in my project.

Once again, thank you for your posts.

Marcelo Barros
June 19, 2009

Yes, your solution avoid any additional costs. But I saw some projects where people just pay for better networks services and real IPs. But this may be a local issue.

Comments RSS TrackBack Identifier URI

Leave a comment