您的位置:首页 > 理论基础 > 计算机网络

网络字节序

2014-03-03 20:49 204 查看
大端模式:从高字节开始存储;小端模式:从低字节开始存储;
网络协议必须协调一致字节序(网络字节序),同时也要考虑到不同主机的实际情况,所以存在二者之间的转换。
常见的函数有 htons,htonl,ntohs,ntohl。

查看主机字节序(UNPv1 P64):
#include<stdio.h>
#include<stdlib.h>

int
main(int argc, char **argv)
{
        union {
                short  s;
                char   c[sizeof(short)];
        } un;//??

        un.s = 0x0102;
        if (sizeof(short) == 2) {
                if (un.c[0] == 1 && un.c[1] == 2)
                        printf("big-endian\n");
                else if (un.c[0] == 2 && un.c[1] == 1)
                        printf("little-endian\n");
                else
                        printf("unknown\n");
        } else
                printf("sizeof(short) = %ld\n", sizeof(short));

        exit(0);
}


点分十进制(presentation)和网络地址结构的二进制格式(numeric)使用 inet_pton , inet_ntop.
#include<arpa/inet.h>
int inet_pton(int family, const char *str, void *addrptr);
const char *inet_ntop(int family, const void *addptr,char *str,size_t len); 注意第二个参数;

简单实现上述功能(IPv4):
#include        <sys/types.h>
#include        <sys/socket.h>
#include        <netinet/in.h>
#include        <arpa/inet.h>
#include        <errno.h>
#include        <string.h>

int
my_inet_pton(int family, const char *strptr, void *addrptr)
{
    if (family == AF_INET) {
        struct in_addr  in_val;

        if (inet_aton(strptr, &in_val)) {
            memcpy(addrptr, &in_val, sizeof(struct in_addr));
int
my_inet_pton(int family, const char *strptr, void *addrptr)
{
    if (family == AF_INET) {
        struct in_addr  in_val;

        if (inet_aton(strptr, &in_val)) {
            memcpy(addrptr, &in_val, sizeof(struct in_addr));
            return (1);
        }
                return(0);
    }
        errno = EAFNOSUPPORT;
    return (-1);
}

const char *
my_inet_ntop(int family, const void *addrptr, char *strptr, size_t len)
{
        const u_char *p = (const u_char *) addrptr;

        if (family == AF_INET) {
                char    temp[INET_ADDRSTRLEN];

                snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
                if (strlen(temp) >= len) {
                        errno = ENOSPC;
                        return (NULL);
                }
                strcpy(strptr, temp);
                return (strptr);
        }
        errno = EAFNOSUPPORT;
        return (NULL);
}

int main(){
        char buf[INET_ADDRSTRLEN]={0};
        struct sockaddr_in addr;
        addr.sin_family=AF_INET;
        addr.sin_addr.s_addr = inet_addr("192.168.4.135");
        printf("%s\n",my_inet_ntop(AF_INET,(const void *)&addr.sin_addr,buf,sizeof(buf)));
//      printf("%s\n",inet_ntop(AF_INET,(const void *)&addr.sin_addr,buf,sizeof(buf)));
        return 0;
}




对于上面的调用必须确定是IPv4或IPv6的地址(&addr6.sin6_addr)可以利用包裹函数,通用处理(sock_ntop):
#include "util.h"

#ifdef  H***E_SOCKADDR_DL_STRUCT
#include        <net/if_dl.h>
#endif

/* include sock_ntop */
char *
sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
    char                portstr[8];
    static char str[128];               /* Unix domain is largest */

        switch (sa->sa_family) {
        case AF_INET: {
                struct sockaddr_in      *sin = (struct sockaddr_in *) sa;

                if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL)
                        return(NULL);
                if (ntohs(sin->sin_port) != 0) {
                        snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port));
                        strcat(str, portstr);
                }
                return(str);
        }
/* end sock_ntop */

#ifdef  IPV6
        case AF_INET6: {
                struct sockaddr_in6     *sin6 = (struct sockaddr_in6 *) sa;

                str[0] = '[';
                if (inet_ntop(AF_INET6, &sin6->sin6_addr, str + 1, sizeof(str) - 1) == NULL)
                        return(NULL);
                if (ntohs(sin6->sin6_port) != 0) {
                        snprintf(portstr, sizeof(portstr), "]:%d", ntohs(sin6->sin6_port));
                        strcat(str, portstr);
                        return(str);
                }
                return (str + 1);
        }
#endif

#ifdef  AF_UNIX
        case AF_UNIX: {
                struct sockaddr_un      *unp = (struct sockaddr_un *) sa;

                        /* OK to have no pathname bound to the socket: happens on
                           every connect() unless client calls bind() first. */
                if (unp->sun_path[0] == 0)
                        strcpy(str, "(no pathname bound)");
                else
                        snprintf(str, sizeof(str), "%s", unp->sun_path);
                return(str);
        }
#endif

#ifdef  H***E_SOCKADDR_DL_STRUCT
        case AF_LINK: {
                struct sockaddr_dl      *sdl = (struct sockaddr_dl *) sa;

                if (sdl->sdl_nlen > 0)
                        snprintf(str, sizeof(str), "%*s (index %d)",
                                         sdl->sdl_nlen, &sdl->sdl_data[0], sdl->sdl_index);
                else
                        snprintf(str, sizeof(str), "AF_LINK, index=%d", sdl->sdl_index);
                return(str);
        }
#endif
        default:
                snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d",
                                 sa->sa_family, salen);
                return(str);
        }
    return (NULL);
}

char *
Sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
        char    *ptr;

        if ( (ptr = sock_ntop(sa, salen)) == NULL)
                perror("sock_ntop error");      /* inet_ntop() sets errno */
        return(ptr);
}


测试:
#include "util.h"

int main(){
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr("192.168.4.135");
        addr.sin_port = htons(13);

        printf("%s\n",Sock_ntop((const struct sockaddr *)&addr,sizeof(addr)));
        return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: