Get total KB/s from command line

Discussion in 'Mac Programming' started by Erve, Jun 19, 2014.

  1. Erve macrumors newbie

    Joined:
    Jun 19, 2014
    #1
    I'm trying to get a similar output to that of Activity Monitor's total network In/Out KB/s via the command line.

    However, I can't use sudo, which rules out lsof and netstat's -w option results in "streaming" output: I need a command which returns/prints the total In/Out KB/s for en0 (wifi), then "ends" (i.e. doesn't "stream").

    Is this possible? I've no objection to installing a third-party command via homebrew if there's a suitable tool out there.

    Thanks!

    EDIT: I know iStat Menus (and Activity Monitor) offer this, but I need to be able to call this script from another application and parse the output, so those apps don't help in this case.
     
  2. robvas macrumors 68020

    Joined:
    Mar 29, 2009
    Location:
    USA
    #2
  3. mfram, Jun 20, 2014
    Last edited: Jun 20, 2014

    mfram macrumors 65816

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #3
    This source code is based on the netstat utility source on Apple's Open Source website. Pass in an interface name on the command-line. Defaults to 'en0'. Computes the input and output bytes per second over a 2 second interval.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/sysctl.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <net/if.h>
    #include <net/if_var.h>
    #include <net/if_dl.h>
    #include <net/if_types.h>
    #include <net/if_mib.h>
    #include <net/route.h>
    
    #include <netinet/in.h>
    #include <netinet/in_var.h>
    #include <unistd.h>
    
    static u_int64_t opackets = 0;
    static u_int64_t ipackets = 0;
    static u_int64_t obytes = 0;
    static u_int64_t ibytes = 0;
    
    int 
    get_stats(char *interface)
    {
    	int		ret = 0;
    	char		name      [32];
    	int		mib        [6];
    	char           *buf = NULL, *lim, *next;
    	size_t		len;
    	struct if_msghdr *ifm;
    	unsigned int	ifindex = 0;
    
    	if (interface != 0)
    		ifindex = if_nametoindex(interface);
    
    	mib[0] = CTL_NET;
    	mib[1] = PF_ROUTE;
    	mib[2] = 0;
    	mib[3] = 0;
    	mib[4] = NET_RT_IFLIST2;
    	mib[5] = 0;
    
    	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
    		return ret;
    	if ((buf = malloc(len)) == NULL) {
    		printf("malloc failed\n");
    		exit(1);
    	}
    	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
    		if (buf)
    			free(buf);
    		return ret;
    	}
    	lim = buf + len;
    	for (next = buf; next < lim;) {
    		ifm = (struct if_msghdr *)next;
    		next += ifm->ifm_msglen;
    
    		if (ifm->ifm_type == RTM_IFINFO2) {
    			struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm;
    			struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1);
    
    			strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
    			name[sdl->sdl_nlen] = 0;
    			if (interface != 0 && if2m->ifm_index != ifindex)
    				continue;
    
    			/*
    			 * Get the interface stats.  These may get overriden
    			 * below on a per-interface basis.
    			 */
    			opackets = if2m->ifm_data.ifi_opackets;
    			ipackets = if2m->ifm_data.ifi_ipackets;
    			obytes = if2m->ifm_data.ifi_obytes;
    			ibytes = if2m->ifm_data.ifi_ibytes;
    			if (ret == 0) {
    				printf("%-5.5s %8.8s %10.10s ",
    				       "Name", "Ipkts", "IBytes");
    				printf("%8.8s %10.10s\n", "Opkts", "Obytes");
    				ret = 1;
    			}
    			printf("%-5.5s %-8.8llu ", name, ipackets);
    			printf("%10.10llu ", ibytes);
    			printf("%-8.8llu ", opackets);
    			printf("%10.10llu\n", obytes);
    		}
    	}
    
            free(buf);
    
    	return ret;
    }
    
    int 
    main(int argc, char *argv[])
    {
    	char           *ifname;
    	int		r;
    	int		sleeptime = 2;
    
    	if (argc > 1) {
    		ifname = argv[1];
    	} else {
    		ifname = "en0";
    	}
    
    	r = get_stats(ifname);
    	if (r) {
    		u_int64_t	ib = ibytes;
    		u_int64_t	ob = obytes;
    
    		sleep(sleeptime);
    		get_stats(ifname);
    		printf("%llu %llu\n", (ibytes - ib) / sleeptime, (obytes - ob) / sleeptime);
    	} else {
    		printf("No interface %s\n", ifname);
    	}
    }
    
     
  4. Erve thread starter macrumors newbie

    Joined:
    Jun 19, 2014
    #4
    Thanks mfram!

    We're getting out of my comfort zone here.... How to call this from the command line?
     
  5. mfram macrumors 65816

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #5
    It's C code. It needs to be compiled. I assumed you were familiar with that and could modify it to your needs. I guess not. I'll clean it up, make command-line parameters and post source and an executable.
     
  6. mfram macrumors 65816

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #6
    Updated code with actual command-line parameters. You can specify interface name, and time interval. See the comments.

    Code:
    /*
     * Print interface statistics in bytes per second
     * 
     * Parameters: 
     * -t #		Time interval to compute, default 2 seconds
     * -i <ifname>	Interface name, defaults to 'en0' 
     * -s		Print raw stats
     * 
     * Output: Two numbers separated by a space. First value is input bytes per
     * second. Second value is output bytes per second
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/sysctl.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <net/if.h>
    #include <net/if_var.h>
    #include <net/if_dl.h>
    #include <net/if_types.h>
    #include <net/if_mib.h>
    #include <net/route.h>
    
    #include <netinet/in.h>
    #include <netinet/in_var.h>
    #include <unistd.h>
    
    static u_int64_t opackets = 0;
    static u_int64_t ipackets = 0;
    static u_int64_t obytes = 0;
    static u_int64_t ibytes = 0;
    static int	raw_stats = 0;
    
    int
    get_stats(char *interface)
    {
    	int		ret = 0;
    	char		name      [32];
    	int		mib        [6];
    	char           *buf = NULL, *lim, *next;
    	size_t		len;
    	struct if_msghdr *ifm;
    	unsigned int	ifindex = 0;
    
    	if (interface != 0)
    		ifindex = if_nametoindex(interface);
    
    	mib[0] = CTL_NET;
    	mib[1] = PF_ROUTE;
    	mib[2] = 0;
    	mib[3] = 0;
    	mib[4] = NET_RT_IFLIST2;
    	mib[5] = 0;
    
    	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
    		return ret;
    	if ((buf = malloc(len)) == NULL) {
    		printf("malloc failed\n");
    		exit(1);
    	}
    	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
    		if (buf)
    			free(buf);
    		return ret;
    	}
    	lim = buf + len;
    	for (next = buf; next < lim;) {
    		ifm = (struct if_msghdr *)next;
    		next += ifm->ifm_msglen;
    
    		if (ifm->ifm_type == RTM_IFINFO2) {
    			struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm;
    			struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1);
    
    			strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
    			name[sdl->sdl_nlen] = 0;
    			if (interface != 0 && if2m->ifm_index != ifindex)
    				continue;
    
    			/*
    			 * Get the interface stats.  These may get overriden
    			 * below on a per-interface basis.
    			 */
    			opackets = if2m->ifm_data.ifi_opackets;
    			ipackets = if2m->ifm_data.ifi_ipackets;
    			obytes = if2m->ifm_data.ifi_obytes;
    			ibytes = if2m->ifm_data.ifi_ibytes;
    			if (ret == 0) {
    				ret = 1;
    				if (raw_stats) {
    					printf("%5s %10s %14s ",
    					       "Name", "Ipkts", "IBytes");
    					printf("%10s %14s\n", "Opkts", "Obytes");
    				}
    			}
    			if (raw_stats) {
    				printf("%-5s %10llu ", name, ipackets);
    				printf("%14llu ", ibytes);
    				printf("%10llu ", opackets);
    				printf("%14llu\n", obytes);
    			}
    		}
    	}
    
    	free(buf);
    
    	return ret;
    }
    
    void
    usage(void)
    {
    	printf("arguments:\n\t-t #\t\tTime interval to compute, default 2 seconds\n");
    	printf("\t-i <ifname>\tInterface name, defaults to 'en0'\n");
    	printf("\t-s\t\tPrint raw stats\n");
    	exit(1);
    }
    
    int
    main(int argc, char *argv[])
    {
    	char           *ifname = "en0";
    	int		r;
    	int		sleeptime = 2;
    
    	int		bflag     , ch, fd;
    
    	bflag = 0;
    	while ((ch = getopt(argc, argv, "st:i:")) != -1) {
    		switch (ch) {
    		case 't':
    			sleeptime = atoi(optarg);
    			if (sleeptime < 1) {
    				sleeptime = 1;
    			}
    			break;
    		case 'i':
    			ifname = optarg;
    			break;
    		case 's':
    			raw_stats = 1;
    			break;
    		default:
    			usage();
    		}
    	}
    	argc -= optind;
    	argv += optind;
    
    	r = get_stats(ifname);
    	if (r) {
    		u_int64_t	ib = ibytes;
    		u_int64_t	ob = obytes;
    		u_int64_t	diffo, diffi;
    
    		sleep(sleeptime);
    		get_stats(ifname);
    		diffo = (obytes - ob) / (u_int64_t) sleeptime;
    		diffi = (ibytes - ib) / (u_int64_t) sleeptime;
    		printf("%llu %llu\n", diffi, diffo);
    	} else {
    		printf("No interface %s\n", ifname);
    	}
    }
    
     

    Attached Files:

  7. mfram macrumors 65816

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #7
    Unzip the netst.zip. Inside is the source code and an executable called 'netst'.

    The executable must be marked executable in the shell. (Only has to be done once.)

    Code:
    $ chmod u+x netst
    $ ./netst
    51939 807
    $ ./netst -i en0 -t 3 -s
     Name      Ipkts         IBytes      Opkts         Obytes
    en0       124326      165387520      52059        6387271
     Name      Ipkts         IBytes      Opkts         Obytes
    en0       124397      165490944      52076        6388885
    34474 538
    
     
  8. Erve thread starter macrumors newbie

    Joined:
    Jun 19, 2014
    #8
    mfram - that works brilliantly, thank you so much!!
     

Share This Page