Mac&iOS Socket 相关备忘 .

struct sockaddr {  

unsigned short sa_family; /* address family, AF_xxx */  

char sa_data[14]; /* 14 bytes of protocol address */  

};  

sa_family是地址家族,一般都是“AF_xxx”的形式。通常大多用的是都是AF_INET,代表TCP/IP协议族。sa_data是14字节协议地址。此数据结构用做bind、connect、recvfrom、sendto等函数的参数,指明地址信息。但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构sockaddr_in(在netinet/in.h中定义):  

struct sockaddr_in {  

short int sin_family; /* Address family */  

unsigned short int sin_port; /* Port number */  

struct in_addr sin_addr; /* Internet address */  

unsigned char sin_zero[8]; /* Same size as struct sockaddr */  

};  

typedef struct in_addr{  

union{  

struct{  

unsigned char s_b1,s_b2,s_b3,s_b4;  

} S_un_b;  

struct{  

unsigned short s_w1,s_w2;  

} S_un_w;  

struct{  

unsigned long S_addr;  

} S_un;  

}  

} IN_ADDR;  

sin_family指代协议族,在socket编程中只能是AF_INET。sin_port存储端口号(使用网络字节顺序)。sin_addr存储IP地址,使用in_addr这个数据结构。sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。s_addr按照网络字节顺序存储IP地址。sockaddr_in和sockaddr是并列的结构,指向sockaddr_in的结构体指针也可以指向sockaddr的结构体,并代替它。也就是说,你可以使用sockaddr_in建立你所需要的信息,然后用bzero函数初始化就可以了

bzero((char*)&mysock,sizeof(mysock));//初始化  

sockaddr_in mysock;  

bzero((char*)&mysock,sizeof(mysock));  

mysock.sa_family=AF_INET;  

mysock.sin_port=htons(1234);//1234是端口号  

mysock.sin_addr.s_addr=inet_addr("192.168.0.1");


struct sockaddr一般有两种定义:
struct sockaddr {
        ushort_t        sa_family;      
        char            sa_data[14];    
};

或者
struct sockaddr {
        uchar_t         sa_len;         
        sa_family_t     sa_family;      
        char            sa_data[14];    
};

后一种是兼容BSD4.3的。


BSD之所以要在socket地址结构体里面定义一个长度字段,是因为BSD代码中需要处理socket地址结构体的代码都是统一的,与协议无关的。根据这个字段就可以知道后面需要处理的地址实际有多长。


http://bbs.csdn.net/topics/10132056

struct sockaddr {
       unsigned short sa_family; /* 地址族, AF_xxx */
       char sa_data[14]; /* 14字节的协议地址*/
   };
   
上面是通用的socket地址,具体到Internet socket,用下面的结构,二者可以进行类型转换
   
struct sockaddr_in {
       short int sin_family; /* 地址族 */
       unsigned short int sin_port; /* 端口号 */
       struct in_addr sin_addr; /* Internet地址 */
       unsigned char sin_zero[8]; /* 与struct sockaddr一样的长度 */
   };
   
   struct in_addr就是32位IP地址。
   
   struct in_addr {
       unsigned long s_addr;
   };

inet_addr()是将一个点分制的IP地址(如192.168.0.1)转换为上述结构中需要的32位IP地址(0xC0A80001)

通常的用法是:
int sockfd;
struct sockaddr_in my_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0); /* 做一些错误检查! */

my_addr.sin_family = AF_INET; /* 主机字节序 */
my_addr.sin_port = htons(MYPORT); /* short, 网络字节序 */
my_addr.sin_addr.s_addr = inet_addr("192.168.0.1");

bzero(&(my_addr.sin_zero), 8); /* zero the rest of the struct */
/* 不要忘了为bind()做错误检查: */
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));


AF_INET


AF 表示ADDRESS FAMILY 地址族   

PF 表示PROTOCOL FAMILY 协议族  

但这两个宏定义是一样的,所以使用哪个都没有关系。Winsock2.h中

#define AF_INET 0  

#define PF_INET AF_INET  

所以在windows中AF_INET与PF_INET完全一样。而在Unix/Linux系统中,在不同的版本中这两者有微小差别。对于BSD,是AF,对于POSIX是PF。UNIX系统支持AF_INET,AF_UNIX,AF_NS等,而DOS,Windows中仅支持AF_INET,它是网际网区域。在函数socketpair与socket的domain参数中有AF_UNIX,AF_LOCAL,AF_INET,PF_UNIX,PF_LOCAL,PF_INET.这几个参数有AF_UNIX=AF_LOCAL, PF_UNIX=PF_LOCAL, AF_LOCAL=PF_LOCAL, AF_INET=PF_INET.  建议:对于socketpair与socket的domain参数,使用PF_LOCAL系列,而在初始化套接口地址结构时,则使用AF_LOCAL. 

例如: z = socket(PF_LOCAL, SOCK_STREAM, 0);

adr_unix.sin_family = AF_LOCAL;


 

sockaddr_in sockaddr in_addr区别联系


sockaddr_in sockaddr in_addr

struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};

struct sockaddr_in {
short int sin_family; // Address family
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[8]; // Same size as struct sockaddr
};

struct in_addr {
unsigned long s_addr; // that’s a 32-bit long, or 4 bytes
};

想来你是要进行网络编程,使用socket, listen, bind等函数。
你只要记住,填值的时候使用sockaddr_in结构,而作为函数的
参数传入的时候转换成sockaddr结构就行了,毕竟都是16个字符
长。

sockaddr的结构是:
struct sockaddr {
  unsigned short sa_family;  /* address family, AF_xxx ,2字节*/
  char sa_data[14];           /* 14 bytes of protocol address ,14字节*/
  };//共16字节

sockaddr_in的结构是:
struct sockaddr_in {
  short int sin_family;  /* Address family ,2字节*/
  unsigned short int sin_port;  /* Port number , 2字节*/
  struct in_addr sin_addr;  /* Internet address ,4字节*/
  unsigned char sin_zero[8];  /* Same size as struct sockaddr ,8字节,*/
  };//共16字节

bzero


原型:extern void bzero(void *s, int n);  

用法:#include <string.h>  

功能:置字节字符串s的前n个字节为零且包括‘\0’。  

说明:bzero无返回值,并且使用strings.h头文件,strings.h曾经是posix标准的一部分,但是在POSIX.1-2001标准里面,这些函数被标记为了遗留函数而不推荐使用。在POSIX.1-2008标准里已经没有这些函数了。推荐使用memset替代bzero。  

举例:  // bzero.c  /* bzero函数TC和VC中都没有,gcc中提供了 */  

#include <stdio.h>  

#include <string.h>  

int main( void )  {  

struct  {  

int a;  

char s[5];  

float f;  

} tt;  

char s[20];  

bzero( &tt, sizeof( tt ) );//等价于memset(&tt,0,sizeof(tt));  

bzero( s, 20 );//等价于memset(s,0,20);  

printf( "Initial success." );  

getchar();  

return 0;  

}


htons()

简述:  将主机的无符号短整形数转换成网络 字节顺序。  

#include <winsock.h>  

u_short PASCAL FAR htons( u_short hostshort);  

hostshort:主机字节顺序表达的16位数。  

注释:  本函数将一个16位数从主机字节顺序转换成网络字节顺序。  

返回值:  htons()返回一个网络字节顺序的值。  

参见:  htonl(),ntohl(),ntohs().  

 ---------------------------------------------  

简单地说,htons()就是将一个数的高低位互换  (如:12 34 --> 34 12)  VB表示:  MsgBox Hex(htons(&H1234))  显示值为 3412  ==============================  

htons() host to network short  

htonl() host to network long  

ntohl() network to host long  

ntohs() network to host short


bcopy


原型:extern void bcopy(const void *src, void *dest, int n);  

用法:#include <string.h>  

功能:将字符串src的前n个字节复制到dest中  

说明:bcopy不检查字符串中的空字节NULL,函数没有返回值。  

举例:  // bcopy.c  

#include <syslib.h>  

#include <string.h>  

main()  {  

char *s="Golden Global View";  

char d[20];  

clrscr(); // clear screen  

bcopy(s,d,6);  

printf("s: %s\n",s);  

printf("d: %s\n",d);  

getchar();  

clrscr();  

s[13]=0;  

bcopy(s+7,d,11); // bcopy ignore null in string  

printf("%s\n",s+7);  

for(i=0;i<11;i++)  

putchar(d);  

getchar();  

return 0;  

}


send()

简述

  向一个已连接的 套接口发送数据。  

#include <winsock.h>  

int PASCAL FAR send( SOCKET s, const char FAR* buf, int len, int flags);  

s:一个用于标识已连接套接口的描述字。  

buf:包含待发送数据的缓冲区。  

len:缓冲区中数据的长度。  

flags:调用执行方式。

注释

  send()适用于已连接的数据包或流式 套接口发送数据。对于数据报类 套接口,必需注意发送数据长度不应超过 通讯子网的IP包最大长度。IP包最大长度在 WSAStartup()调用返回的WSAData的iMaxUdpDg元素中。如果数据太长无法自动通过下层协议,则返回WSAEMSGSIZE错误,数据不会被发送。

  请注意成功地完成send()调用并不意味着数据传送到达。

  如果传送系统的缓冲区空间不够保存需传送的数据,除非套接口处于非阻塞I/O方式,否则send()将阻塞。对于非阻塞SOCK_STREAM类型的套接口,实际写的数据数目可能在1到所需大小之间,其值取决于本地和远端主机的缓冲区大小。可用select()调用来确定何时能够进一步发送数据。

  在相关套接口的选项之上,还可通过标志位flag来影响函数的执行方式。也就是说,本函数的语义既取决于套接口的选项也取决于标志位。后者由以下一些值组成:

值意义

  MSG_DONTROUTE 指明数据不选径。一个WINDOWS 套接口供应商可以忽略此标志;MSG_OOB 发送 带外数据(仅适用于SO_STREAM;)。

返回值

  若无错误发生,send()返回所发送数据的总数(请注意这个数字可能小于len中所规定的大小)。否则的话,返回SOCKET_ERROR错误, 应用程序可通过WSAGetLastError()获取相应 错误代码

错误代码:  

WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。  

WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。  

WSAEACESS:要求地址为广播地址,但相关标志未能正确设置。  

WSAEINTR:通过一个WSACancelBlockingCall()来取消一个(阻塞的)调用。  

WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。  

WSAEFAULT:buf参数不在用户地址空间中的有效位置。  

WSAENETRESET:由于WINDOWS套接口实现放弃了连接,故该连接必需被复位。  

WSAENOBUFS:WINDOWS套接口实现报告一个缓冲区死锁。  

WSAENOTCONN:套接口未被连接。  

WSAENOTSOCK:描述字不是一个套接口。  

WSAEOPNOTSUPP:已设置了MSG_OOB,但套接口非SOCK_STREAM类型。  

WSAESHUTDOWN:套接口已被关闭。一个套接口以1或2的how参数调用shutdown()关闭后,无法再用sned()函数。  

WSAEWOULDBLOCK:

  WSAEMSGSIZE:套接口为SOCK_DGRAM类型,且数据报大于WINDOWS套接口实现所支持的最大值。

  WSAEINVAL:套接口未用bind()捆绑。

  WSAECONNABORTED:由于超时或其他原因引起虚电路的中断。

  WSAECONNRESET:虚电路被远端复位。

  参见:  recv(),recvfrom(), socket(), sendto(), WSAStartup().


recv()

简述:

  从一个 套接口接收数据。

  表头文件:  

#include<sys/types.h>  

#include<sys/socket.h>  

int PASCAL FAR recv( SOCKET s, char FAR* buf, int len, int flags);  

s:一个标识已连接套接口的描述字。  

buf:用于接收数据的缓冲区。  

len:缓冲区长度。  

flags:指定调用方式。

流程:

  这里只描述同步Socket的recv函数的执行流程。当 应用程序调用recv函数时,

  (1)recv先等待s的发送缓冲中的数据被协议传送完毕,如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR,

  (2)如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,直到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的),

  recv函数返回其实际copy的字节数。如果recv在copy时出错,那么它返回SOCKET_ERROR;如果recv函数在等待协议接收数据时网络中断了,那么它返回0。

  注意:在Unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。

实例:

  读数据的时候需要考虑的是当recv()返回的大小如果等于请求的大小,那么很有可能是 缓冲区还有数据未读完,也意味着该次事件还没有处理完,所以还需要再次读取:  while(rs)

{  

buflen = recv(activeevents[i].data.fd, buf, sizeof(buf), 0);  

if(buflen < 0)  

{  // 由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可读

  // 在这里就当作是该次事件已处理处.  

if(errno == EAGAIN)  

break;  

else  return;  

}  

else if(buflen == 0)  

{  // 这里表示对端的socket已正常关闭.  

}  

if(buflen == sizeof(buf))  

rs = 1; // 需要再次读取  

else  rs = 0;  

}

注释:

  本函数用于已连接的数据报或流式 套接口s进行数据的接收。

  对SOCK_STREAM类型的套接口来说,本函数将返回所有可用的信息,最大可达缓冲区的大小。如果套接口被设置为线内接收带外数据(选项为SO_OOBINLINE),且有带外数据未读入,则返回带外数据。应用程序可通过调用ioctlsocket()的SOCATMARK命令来确定是否有带外数据待读入。

  对于数据报类套接口,队列中第一个数据报中的数据被解包,但最多不超过缓冲区的大小。如果数据报大于缓冲区,那么缓冲区中只有数据报的前面部分,其他的数据都丢失了,并且recv()函数返回WSAEMSGSIZE错误。如果没有数据待读,那么除非是非阻塞模式,不然的话套接口将一直等待数据的到来,此时将返回SOCKET_ERROR错误,错误代码是WSAEWOULDBLOCK。用select()或WSAAsynSelect()可以获知何时数据到达。

  如果套接口为SOCK_STREAM类型,并且远端“优雅”地中止了连接,那么recv()一个数据也不读取,立即返回。如果立即被强制中止,那么recv()将以WSAECONNRESET错误失败返回。在套接口的所设选项之上,还可用标志位flag来影响函数的执行方式。也就是说,本函数的语义既取决于套接口选项,也取决于标志位参数。标志位可取下列值:  值 意义

  MSG_PEEK查看当前数据。数据将被复制到缓冲区中,但并不从输入队列中删除。

  MSG_OOB 处理带外数据(参见2.2.3节具体讨论)。

  返回值:

  若无错误发生,recv()返回读入的字节数。如果连接已中止,返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。  错误代码

  WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。

  WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。

  WSAENOTCONN:套接口未连接。

  WSAEINTR:阻塞进程被WSACancelBlockingCall()取消。

  WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。

  WSAENOTSOCK:描述字不是一个套接口

  WSAEOPNOTSUPP:指定了MSG_OOB,但套接口不是SOCK_STREAM类型的。

  WSAESHUTDOWN:套接口已被关闭。当一个套接口以0或2的how参数调用shutdown()关闭后,无法再用recv()接收数据。

  WSAEWOULDBLOCK:套接口标识为非阻塞模式,但接收操作会产生阻塞。

  WSAEMSGSIZE:数据报太大无法全部装入缓冲区,故被剪切。

  WSAEINVAL:套接口未用bind()进行捆绑。

  WSAECONNABORTED:由于超时或其他原因,虚电路失效。

  WSAECONNRESET:远端强制中止了虚电路。

你可能感兴趣的:(Mac&iOS Socket 相关备忘 .)