基于Python的Socket程序接收libPcap(C语言)数据

0 投票
1 回答
827 浏览
提问于 2025-04-17 14:32

大家好:

我在用基于Python的socket客户端发送字符串数据(比如日志数据)。

同时,我在服务器端使用libpcap来捕获字符串数据

但是当我第二次向服务器发送字符串数据时,客户端出现了错误。

错误信息如下:

Traceback (most recent call last):
  File "./udp_client_not_sendback.py", line 21, in <module>
    s.sendall(data) #Send UDP data
  File "/usr/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 111] Connection refused

下面是我在客户端和服务器端的代码:

客户端(Python)

import socket, sys

host = sys.argv[1] #Server IP Address

textport = sys.argv[2] #Server Binding Port

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #socket

try:
    port = int(textport)
except ValueError:
    port = socket.getservbyname(textport, 'udp')

s.connect((host, port)) #connect

while(1):
    print "Enter data to transmit:"

    data = sys.stdin.readline().strip() #UDP data

    s.sendall(data) #Send UDP data

服务器端(C语言libpcap)

    pcap_handler_func(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
    {
    char timebuf[64];
    char addrstr[64];
    struct ether_header *ethhdr = (struct ether_header *)bytes;
    struct iphdr *ipv4h;
    struct ip6_hdr *ipv6h;
    
    memset(timebuf, 0, sizeof(timebuf));
    if (ctime_r(&h->ts.tv_sec, timebuf) == NULL) {
    return;
    }
    timebuf[strlen(timebuf) - 1] = '\0';
    printf("%s, caplen:%d, len:%d, ", timebuf, h->caplen, h->len);
    ipv4h = (struct iphdr *)(bytes + sizeof(struct ether_header));
    inet_ntop(AF_INET, &ipv4h->saddr, addrstr, sizeof(addrstr));
    printf("src[%s]\n", addrstr);

    return;
    }

    int main()
    {
    pcap_t *p;
    char errbuf[PCAP_ERRBUF_SIZE];
    char cmdstr[] = "udp";
    struct bpf_program bpfprog;
    
    p = pcap_open_live("eth1", 65536, 1, 10, errbuf);

    //Filter
    if (pcap_setfilter(p, &bpfprog) < 0) {
    fprintf(stderr, "%s\n", pcap_geterr(p));
    return 1;
    }

    //Packet action
    if (pcap_loop(p, -1, pcap_handler_func, NULL) < 0) {
    fprintf(stderr, "%s\n", pcap_geterr(p));
    pcap_close(p);
    return 1;
    }

    pcap_close(p);
    return 0;
    }

我觉得问题出在我没有在服务器端绑定socket,只是用pcap来捕获字符串数据。

所以在第二次发送时,客户端就出现了socket错误。

有没有人能给我一些建议来解决这个问题?

非常感谢你的帮助。

1 个回答

0

libpcap和它使用的捕获机制并不适合用来编写TCP/UDP/IP服务器!它们的主要用途是1) 被动捕获数据包(在某些情况下,使用更新版本的libpcap还可以注入数据包),以及2) 在用户模式下实现一些在链路层之上运行的协议,这些协议在操作系统内核中没有实现。

如果你在某台机器上运行一个程序,使用libpcap监听数据包,这并不会在那台机器上创建一个套接字来接收发送到某个特定TCP或UDP端口的数据包。

当你的程序第一次尝试向那个UDP端口发送数据包时,接收方的机器可能会发现没有套接字在监听这个UDP端口,于是它会返回一个ICMP端口不可达的消息。发送操作已经完成;UDP是一种无连接的协议,没有可靠的传输保证,所以UDP发送操作并不会等待任何回复——只要数据包成功发送出去,就算是“成功”,因为在UDP层面上没有其他的成功交付检查。

不过,当你在客户端程序中连接了套接字后,如果客户端机器的ICMP实现看到这个ICMP端口不可达的消息,就会在套接字上设置一个指示,告诉程序之前发送的UDP数据包无法送达(因为没有接收方)。在这个套接字上尝试接收数据,或者似乎在这个套接字上再次尝试发送数据包时,会返回“连接被拒绝”的错误,表示之前发送的数据包无法送达。这也意味着第二次尝试发送数据包实际上不会发送;你需要再尝试一次,这次我认为会成功发送数据包,尽管如果服务器上没有程序在监听那个UDP端口,依然会收到ICMP端口不可达的消息。

所以这就是为什么你在使用libpcap的嗅探器(而不是服务器!)应用中看到第一个数据包,但没有看到第二个数据包的原因。

所以millimoose说“服务器端必须有一个实际的服务器在运行”是100%正确的。写一个服务器——使用常规的套接字,而不是libpcap及其可能使用的任何机制(在Linux上是AF_PACKET套接字,在*BSD和OS X上是BPF设备等),并在服务器机器上运行它。你也可以同时运行基于libpcap的嗅探器程序,或者其他嗅探器程序,比如tcpdump或{Wireshark, TShark},来查看网络上发生了什么。

撰写回答