Unix网络编程(1)——socket一窥

套接口地址结构

IPv4的套接口地址结构为:编程

struct sockaddr_in
{
    uint8_t sin_len;
    sa_family_t sin_family;
    struct in_addr sin_addr;
    char sin_zero[8];
};

其中最重要的部分当属sin_addr结构体。这个结构体只有一个元素就是类型为in_addr_t的32bit的IPv4地址。安全

struct in_addr
{
    in_addr_t s_addr;
};

所以假设有一个地址结构addr,要取得地址,addr.in_addr获得的是一个in_addr类型的结构体;addr.in_addr.s_addr取得的是一in_addr_t 的地址(一般是32位的整数)。数据结构

套接口地址结构在传递给套接口函数的时候,老是以指针的方式传递。当函数支持不一样类型协议时,如何声明函数参数类型使得通用呢?在ANSI C的无类型指针void *出现以前就解决了这个问题。定义了一个标准的通用套接口地址结构:socket

struct sockaddr
{
    uint8_t sin_len;
    sa_family_t sa_family;
    char sa_data[14];
};

用户在使用一些用通用结构类型做为参数的时候必须进行强制类型转换(struct sockaddr *),不然编译器在检查参数时会给出警告。而内核在处理函数传入的参数时,经过sockaddr中的sa_family来肯定传入结构的具体类型。函数

 

值-结果参数

首先要搞清楚为什么在socket编程中,结果参数有两个传递方向:从进程到内核和从内核到进程。咱们一般见到的bind,connect,sendto,accept,recvfrom等函数都是系统调用,系统调用时内核提供的函数,也是用户程序和内核之间的接口。用户程序在使用系统调用的时候,一般会采用软中断的方式陷入到内核中再经过系统调用实现函数的功能。ui

从进程到内核传递套接口地址结构的函数有bind,connect和sendto.用户程序在调用这些函数的时候,将函数的参数传递给内核处理,用户调用这些函数要拷贝多少数据量固然是知道的(换句话说,用户要求内核拷贝多少数据量确定是知道的),所以函数传递的参数是结构的具体大小。如connect所示:spa

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

而当函数如accept、recvfrom等在调用时,内核须要向进程返回处理结果,函数调用时传入的参数是指向结构大小的指针,这个值仅仅是为了防止内核越界,在执行完成以后,内核将返回储存的大小,所以在传入是一个值,函数执行完成以后,将实际的值写入返回时修改指针指向的大小做为返回值,这时是结果。指针

 

不可重入函数

本节不止一次提到一个概念:函数不可重入。到底怎样才算可重入函数呢?code

可重入,顾名思义就是能够重复进入。能够重复进入意味着函数能够被不一样的进程调用,而且数据不会出现问题。或者换个说法,可重入的函数能够在任什么时候候被中断去执行另一个任务而不会出现问题。所以在写可重入函数时,要保证几点:blog

  • 最好不要使用全局变量。若是非要使用,必须用锁或者信号量对变量进行保护。
  • 不使用静态变量。
  • 不调用不可重入函数。
  • 保证中断的安全。

不可重入函数基本有下面几类:

  • 函数体内使用了静态的数据结构。
  • 函数体内使用了全局变量。
  • 函数体内调用了malloc()或者free()函数。
  • 函数体内调用了标准I/O函数。标准io库不少实现都以不可重入的方式使用全局数据结构。
  • 进行了浮点运算.许多的处理器/编译器中,浮点通常都是不可重入的。
相关文章
相关标签/搜索