UNIX网络编程-结构体和相关函数

28 篇文章 0 订阅

目录

相关结构体

值-结果参数

字节排序函数

字节操纵函数

一些扩展的辅助函数


 

 

相关结构体

IPv4结构体

除非涉及路由套接字,否则不用设置和检查 sin_len 字段
POSIX规范只要求结构中的3个字段,sin_family,sin_addr,sin_port

sin_family对应的是 sa_family_t
sin_port  对应的是 in_port_t
sin_addr  对应的是in_addr结构体,in_addr包含了唯一一个字段,类型是 in_arr_t

其他类型的 u_char,u_shrot,u_int,u_long都是无符号的,但都过时了
IPv4地址和TCP或UDP端口号再套接字地址中总是以网络字节序来存储的
32位IPv4地址存在两种访问方式
1.serv.sin_addr 将按in_addr结构音乐其中的32位IPv4地址
2.serv.sin_addr_s_addr将按in_addr_t(通常是一个无符号的32位整数)引用同一个32位IPv4地址
我们必须正确的使用IPv4地址,尤其在将他作为函数的参数时,因为编译器对传递结构和传递整数的处理是
完全不同的

<netinet/in.h>
struct in_addr {
    in_addr_t s_addr;  /* 32-bit IPv4 address, network byte ordered */
}

struct sockaddr_in {
    uint8-t      sin_len;     /*  length of structure */
    sa_family_t  sin_family;  /*  AF_INET  */
    in_port_t    sin_port     /* 16 bit TCP or UDP port number network byte ordered */
    struct in_addr sin_addr;  /* 32-bit IPv4 address network byte ordered */
    char        sin_zero[8];  /* unused */
}

POXIS规范要求的数据类型

数据类型说明头文件
int8_t带符号的8位整数<sys/types.h>
uint8_t无符号的8位整数<sys/types.h>
int16_t带符号的16位整数<sys/types.h>
uinit16_t无符号的16位整数<sys/types.h>
int32_t带符号的32位整数<sys/types.h>
uint32_t无符号的32位整数<sys/types.h>
sa_family_t套接字地址结构的地址族<sys/socket.h>
socklen_t套接字地址结构的长度,一般为uint32_t<sys/socket.h>
in_addr_t

IPv4地址,一般为uint32_t

<netinet/in.h>
in_port_tTCP或UDP端口,一般为uint16_t<netinet/in.h>

 


通用套接字地址结构

当作为一个参数传递进任何套接字函数时,套接字地址结构总是以引用形式(也就是以指向该结构的指针)来传递,然后以这样的指针作为参数之一的任何套接字必须处理来自所支持的任何协议族的套接字地址结构
在如何生命所传递的数据类型上存在一个问题,ANSI C后解决办法很简单 void * 是通用的指针类型,然而套接字函数是在ANSI C之前定义的,采用的办法是定义一个通用的套接字地址结构

<sys/socket.h>
struct sockaddr {
    uint8_t      sa_len;
    sa_family_t  sa_family;      /* address family: AF_xxx value */
    char         sa_data[14];    /* protocol-specific address */
}

bind 函数的原型就是

int bind(int, struct sockaddr *, socklen_t);


IPv6套接字地址结构

<netinet/in.h>
struct in6_addr {
    unit8_t  sa_addr[16];
};

#define SIN6_LEN    /* required for compile-time tests */

struct sockaddr_in6 {
    uint8_t      sin6_len;     /* length of this struct */   
    sa_family_t  sin6_family;  /* AF_INT6 */
    in_port_t    sin6_port;    /* transport layer port network byte ordered */
    uint32_t     sin6_flowinfo;/* flow information, undefined */
    struct in6_addr sin_addr;  /* IPv6 address network byte ordered */
    uint32_t     sin6_scope_id /* set of interface for a scope */
};

 

套接字地址结构比较

对比IPv4,IPv6,unix域套接字,数据链路和存储
前两种长度是固定的,unix域套接字和数据链路结构是可变长度的

 


值-结果参数

从近处到内核参数套接字地址结构的函数有3个,bind,connect,sendto
比如

struct sockaddr_in serv;
connect(sockfd,(struct sockaddr *)&serv, sizeof(serv));

从内核到进程传递套接字地址结构的函数有4个,accept,recvfrom,getsockname,getpeername
比如

struct sockaddr_un cli;
socklen_t len;
len = sizeof(cli);
getpeername(unixfd, (struct sockaddr *)&cli, &len);

 

 

字节排序函数

大端小端测试


打印当前机器是小头派还是大头派类型
注意,如果没有加这两个头文件
#include <stdio.h>
#include <stdlib.h>
编译时候会报  警告:隐式声明与内建函数‘printf’不兼容   这个错误
编译: gcc -o byteorder byteorder.c

#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) = %d\n",sizeof(short));  
    }  
    return 0;  
  
}  


主机自己和网络字节序之间的相互转换 函数

#include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue);
uint32_t htonl(uint32_t host32bitvalue);
uint16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);

n代表host,n代表network,s代表short,l代表long

 

 


字节操纵函数

Berkely的函数

#include <strings.h>
void bzero(void *dest, size_t nbytes);
void bcopy(const void *str, void *dest, size_t nbytes);
int bcmp(const void *ptr1, const void *prt2, size_t nbytes);

ANSI C的函数

#include <string.h>
void *memset(void *dest, int c, size_t len);
void *memcpy(void *dest, const void *str, size_t nbytes);
int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);


地址转换函数

#include <arpa/inet.h>

//将strptr所指的字符串换成32位的网络字节序二进制值,并保存到到addrptr中
int inet_aton(const char *strptr, struct in_addr *addrptr);

//将字符串转为32位二进制网络字节序的IPv4地址
in_addr_t inet_addr(const char *strptr);

//返回指向一个点分十进制数串的指针
char *inet_ntoa(struct in_addr inadr);

新的地址转换函数

#include <arpa/inet.h>
//family可以是AF_INET,也可以使AF_INET6,将strptr指针指向的字符串,换成二进制值保存到addrptr中
int inet_pton(int family, const char *strptr, void *addrptr);

//将数值格式addrptr转换到哦表达式格式strptr,len是目标存储单元的大小
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

 

10进制ip到二进制转换的例子

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
int main (void) {  
    char IPdotdec[20]; /* 存放点分十进制IP地址  */
    struct in_addr s; /* IPv4地址结构体  */
    /* 输入IP地址  */
    printf("Please input IP address: ");  
    scanf("%s", IPdotdec);  
    /* 转换  */
    inet_pton(AF_INET, IPdotdec, (void *)&s);  
    printf("inet_pton: 0x%x\n", s.s_addr); /* 注意得到的字节序  */
    /* 反转换  */
    inet_ntop(AF_INET, (void *)&s, IPdotdec, 16);  
    printf("inet_ntop: %s\n", IPdotdec);  
  
}  


设置sin_addr 变量的列子,从结果看
sockaddr_in.sin_addr 和 sockaddr_in.sin_addr.s_addr 这两种方式读取结果是一样的

#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>

int main(int argc, char *argv[]) {

    //struct sockaddr_in *addr = malloc(sizeof(struct sockaddr_in));
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9527);
    //addr->sin_addr = inet_pton(
    inet_pton(AF_INET, "47.98.18.8",&addr.sin_addr.s_addr);

    printf("af->port %d\n",addr.sin_port);
    printf("af-addr %d\n", addr.sin_addr);   
    printf("af-addr %d\n", addr.sin_addr.s_addr);   
  
    printf("############################################\n");
    struct sockaddr_in addr_1;
    addr_1.sin_family = AF_INET;
    addr_1.sin_port = htons(8080);
    inet_pton(AF_INET, "192.168.1.100", &addr_1.sin_addr);
    printf("af->port %d\n", addr_1.sin_port);
    printf("af->addr %d\n", addr_1.sin_addr);
    printf("af->addr %d\n", addr_1.sin_addr.s_addr);
    
    
    struct sockaddr_in *addr_2 = malloc(sizeof(struct sockaddr_in));
    addr_2->sin_family = AF_INET;
    addr_2->sin_port = htons(1234);
    inet_pton(AF_INET, "1.2.3.4", &(addr_2->sin_addr));

    printf("======================\n");
    printf("af->port %d\n",addr_2->sin_port);
    printf("af-addr %d\n", addr_2->sin_addr.s_addr);   
    printf("af->addr %d\n",addr_2->sin_addr);
    return 0;
}

//执行结果
af->port 14117
af-addr 135422511
af-addr 135422511
############################################
af->port 36895
af->addr 1677830336
af->addr 1677830336
======================
af->port 53764
af-addr 67305985
af->addr 67305985

 

一些扩展的辅助函数

一次读n个字节的read函数

#include <stdio.h>  
#include <stdlib.h>  
#include <netinet/in.h>  
#include <unistd.h>  
#include <fcntl.h>  
  
ssize_t readn(int fd,void *vptr, size_t n) {  
    size_t nleft;  
    ssize_t nread;  
    char *ptr;  
  
    ptr = vptr;  
    nleft = n;  
    while(nleft > 0) {  
        if( (nread=read(fd,ptr,nleft)) < 0) {  
            if(nread > 0) {  
                nread = 0;  
            } else {  
                return -1;  
            }  
        }  
        else if(nread == 0) {  
            break;  
        }  
        nleft -= nread;  
        ptr += nread;     
    }         
    return (n-nleft);  
}             
                      
int main(int argc, char **argv) {  
                
    int r_fd=open("/data0/test/test.log",O_RDONLY);  
    char buf[100];  
    readn(r_fd,buf,20);   
    printf("%s\n",buf);  
      
    return 0;  
}  

 

一次写入n个字节的write函数

#include <stdio.h>  
#include <stdlib.h>  
#include <netinet/in.h>  
#include <unistd.h>  
#include <fcntl.h>  
  
  
ssize_t writen(int fd, const void *vptr, size_t n) {  
    size_t nleft;  
    ssize_t nwritten;  
    const char *ptr;  
  
    ptr = vptr;  
    nleft = n;  
    while(nleft > 0) {  
        if( (nwritten = write(fd,ptr,nleft)) <= 0) {  
            if(nwritten <0) {  
                nwritten = 0;  
            }  
            else {  
                return -1;  
            }  
        }  
        nleft -= nwritten;  
        ptr += nwritten;  
    }  
    return n;  
}  
  
int main(int argc, char **argv) {  
    int w_fd = open("/data0/test/write.log",O_WRONLY|O_CREAT,0755);  
    writen(w_fd,"test he he",10);  
    return 0;  
}  

 

一次读取一行的read函数

#include <stdio.h>  
#include <stdlib.h>  
#include <netinet/in.h>  
#include <unistd.h>  
#include <fcntl.h>  
  
ssize_t readline(int fd, void *vptr, size_t maxlen) {  
    ssize_t n,rc;  
    char c, *ptr;  
  
    ptr = vptr;  
    for(n=1;n<maxlen;n++) {  
        if( (rc=read(fd,&c,1)) ==1) {  
            *ptr++ = c;  
            if(c=='\n') {  
                break;  
            }  
        }  
        else if(rc == 0) {  
            *ptr = 0;  
            return (n-1);  
        }  
        else {  
            if(rc < 0) {  
                continue;  
            }  
            return -1;  
        }  
  
    }  
    *ptr = 0;  
    return n;  
  
}  
  
int main(int argc, char **argv) {  
    int r_fd=open("/data0/test/test.log",O_RDONLY);  
    char buf[100];  
    readline(r_fd,buf,20);  
    printf("%s\n",buf);  
    return 0;  
}  

一次读一行的read函数(加入缓存的改进版)

#include <stdio.h>  
#include <stdlib.h>  
#include <netinet/in.h>  
#include <unistd.h>  
#include <fcntl.h>  
#include <errno.h>  
#define MAX_LINE 10240

static int read_cnt;
static char *read_ptr;
static char read_buf[MAX_LINE];

size_t my_read(int fd, char*ptr) {
    if(read_cnt <= 0) {
        again:
        if( (read_cnt = read(fd,read_buf,sizeof(read_buf))) < 0 ) {
            if(errno == EINTR) {
                goto again;
            }
            return (-1);
        } else if( read_cnt == 0) {
            return (0);
        }
        read_ptr = read_buf;
    }
    read_cnt--;
    *ptr = *read_ptr++;
    return(1);
}
 
ssize_t readline(int fd, void *vptr, size_t maxlen) {  
    ssize_t n,rc;  
    char c, *ptr;  
  
    ptr = vptr;  
    for(n=1;n<maxlen;n++) {  
        if( (rc=my_read(fd,&c)) ==1) {  
            *ptr++ = c;  
            if(c=='\n') {  
                break;  
            }  
        }  
        else if(rc == 0) {  
            *ptr = 0;  
            return (n-1);  
        }  
        else {  
            return -1;  
        }  
    }  
    *ptr = 0;  
    return n;  
}  


  
int main(int argc, char **argv) {  
    int r_fd=open("/data0/test/test.log",O_RDONLY);  
    char buf[100];  
    readline(r_fd,buf,20);  
    printf("%s\n",buf);  
    return 0;  
} 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值