用pack实现UDP包在PYTHON与C结构体透明通信
Python是一个好东西,是如此的适合写身边的一些小toolkit。测试程序就是其中一例。比如用C写了一个server,就可以用python写一个client来测试这个server。但遇到一个小问题,就是在UDP传输的时候UDP包中信息的各个字段是用结构体定义的。但Python本身是模糊类型的动态语言,怎么样才能构造UDP包的时候符合C语言结构体的结构呢。Yahoo search找到这篇文章,才想起来perl和php也是有这个pack函数的,以前看到这个函数的时候都是略过,没想到有啥具体用处。看来自己还是一根墙上芦苇啊,BS自己一下。
顺便改出两段简陋的code来说明这个问题.
顺便改出两段简陋的code来说明这个问题.
/* * udpsrv.c * * The test udp server, source code is stolen from UNP 3ed ED. * */ #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <strings.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> typedef struct my_data { char name[10]; int age; float score; } MY_DATA; void dg_echo(int, struct sockaddr *, socklen_t); int main(int argc, char **argv) { int sockfd; struct sockaddr_in svraddr, cliaddr; sockfd = socket(AF_INET, SOCK_DGRAM, 0); bzero(&svraddr, sizeof(svraddr)); svraddr.sin_family = AF_INET; svraddr.sin_addr.s_addr = htonl(INADDR_ANY); svraddr.sin_port = htons(3000); bind(sockfd, (struct sockaddr *) &svraddr, sizeof(svraddr)); dg_echo(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)); } void dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen) { int n; socklen_t len; MY_DATA mydata; bzero(&mydata, sizeof(MY_DATA)); for( ; ; ) { len = clilen; n = recvfrom(sockfd, &mydata, sizeof(MY_DATA), 0, pcliaddr, &len); printf("Name:%s\tAge:%d\tScore:%f\n", mydata.name, mydata.age, mydata.score); } }
#!/usr/bin/python # Filename: udpcli.py # a simple udp client import socket, struct hostname = 'localhost' port = 3000 host = socket.gethostbyname(hostname) name = 'sleetdrop' age = 18 score = 100 buf = struct.pack("10sif", name, age, score) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.sendto(buf, (host, port))
在linux上编译并起动udp服务器 $gcc udpsrv.c -o udpsrv $./udpsrv 在另一个term执行 $python udpcli.py 在服务器所在term会得到如下输出: Name:sleetdrop Age:18 Score:100.000000
评论:
pack/unpack的确很强大, python真有魅力, 你终于也开始贴代码了.
Posted by: wf | 2008年05月05日 下午05时28分