socket函数和I/O函数的一些知识点

68 篇文章 0 订阅
7 篇文章 0 订阅

一.socket地址 以及 ip地址转换

#include<bits/socket.h>

struct sockaddr {
  unsigned short sa_family; /* address family, AF_xxx */
  char sa_data[14]; /* 14 bytes of protocol address */
  };
说明:
    sa_family :是2字节的地址家族,一般都是“AF_xxx”的形式。通常用的都是AF_INET。
  sa_data : 是14字节的协议地址。

    AF_UNIX要108个字节,AF_INET要6个字节存,AF_INET6要26个字节存

 

因为存不下AF_UNIX和AF_INET6 就有了structsockaddr_storage;它都可以存得下

同时还有专用地址

1.AF_INET:ipv4的(转自http://blog.csdn.net/angle0615303/article/details/7657267

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;//in_addr_t s_addr;
};


struct in_addr {
union {
    struct { u_char s_b1,s_b2,s_b3,s_b4;} S_un_b;
    struct { u_short s_w1,s_w2;} S_un_w;
    u_long S_addr;//成员s_addr为长整形结构或者 in_addr_t s_addr;
   } S_un;
};

ip转换

  a。利用u_long htonl(u_long hostlong);将主机字节序转换为TCP/IP网络字节序.
  b。利用u_short htons(u_short hostshort);将主机字节序转换为TCP/IP网络字节序.

  c。intinet_aton(const char *string, struct in_addr*addr);如果这个函数成功,函数的返回值非零,如果输入地址不正确则会返回零。使用这个函数并没有错误码存放在errno中,所以它的值会被忽略。结果存在addr参数里面。

   d。原型:in_addr_t inet_addr(constchar *cp);

    参数:字符串,一个点分十进制的IP地址
      
返回值:
      
如果正确执行将返回一个无符号长整数型数。如果传入的字符串不是一个合法的IP地址,将返回INADDR_NONE
      
头文件:Winsock2.h.
       arpa/inet.h
Linux)

e函数声明:char *inet_ntoa(struct in_addr);
    返回点分十进制的字符串在静态内存中的指针。
    所在头文件:<arpa/inet.h>
    函数功能:将网络地址转换成“.”点隔的字符串格式。返回字符串指向函数内部一静态内存,不可重入。

可重入版本:。

void socketaddr_toa(struct in_addr addr,char *ipaddr)

{

     unsigned char *p=(unsigned char)&(addr->sin_addr.s_addr);

     sprintf(ipaddr,"%u.%u.%u.%u.",p[0],p[1],p[2],p[3])

}

F. ipv6 和ipv4 都可以用

 #include<sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    int inet_pton(int af, const char *src, void *dst);

 const char*inet_ntop(int af, const void *src, char *dst, socklen_t cnt);

这个函数转换网络二进制结构到ASCII类型的地址,参数的作用和inet_pton相同,只是多了一个参数socklen_t cnt,他是所指向缓存区dst的大小,避免溢出,如果缓存区太小无法存储地址的值,则返回一个空指针,并将errno置为ENOSPC。

 

通常的用法是:
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″);

2.socketadd_in16 是ipv6专用socket地址,socket_un 是AF_UNIX专用地址

3.所有socket API用的socket地址都是sockaddr ,所有最后socketaddr_in;socketaddr_in6,socketaddr_un;socketaddr_storage又要强制转换成sockaddr


E。通过socket过去远端ip地址:getpeername函数

获取自己的ip地址getsockname函数


二.socket的几个函数

1.int socket(int domain,int type,int protocol);
第一个参数domain设置为“AF_INET”。
第二个参数是套接口的类型:SOCK_STREAM或SOCK_DGRAM。自2.6.17起 type可以使上述两个宏与SOCK_NONBLOCK(非阻塞)和SOCK_CLOEXEC(在fork创建子进程后,在子进程中关闭socket)相与的值。在此版之前 要用fcntl实现非阻塞,子进程关闭

第三个参数设置为0。
系统调用socket()只返回一个套接口描述符,如果出错,则返回-1


2.accept函数只是从listen的监听队列里面取出连接,而现在连接处于何种状态(即使客户端的连接已经关闭)它都不管


3.关闭连接函数:close函数只是socket描述符减一,int shutdown(int sockfd,int howto)不将引用计数减一,而是根据howto来终止连接,失败返回-1,

howto:SHUT_RD 缓冲区中数据丢失,从此不可读,SHUT_RW 发送完缓冲区中数据后不可写;SHUT_RDWR


4.接收带外数据 int sockat(int sockfd)下一个读到的数据是带外数据,返回1,不是则0.

若是1,那么接下来我们可以用MSG_OOB 标志的 recv函数来接收


5.获取地址信息

int getsockname(int s, struct sockaddr *name, socklen_t *namelen);
Get the current name for the specified socket.
获取本地套接口的名字,包括它的IP和端口。

int getpeername(int s, struct sockaddr *name, socklen_t *namelen);
Get the name of connected peer socket.
获取远程套接口的名字,包括它的IP和端口。

getsockname()在指定的套接口绑定地址和端口后才能调用,即服务器在bind()后可调用,
客户端在bind()或connect()之后可调用。getpeername()在连接建立之后才可调用。

6.设置绑定的ip地址可重用:http://blog.csdn.net/tody_guo/article/details/5972588;http://blog.csdn.net/evil_darker/article/details/4602263

可以通过setsockopt(2)函数来设计套接口选项。这个函数的概要如下:
#include <sys/types.h>
#include <sys/socket.h>
int setsockopt(int s,int level,int optname,const void *optval,socklen_t optlen);

setsockopt函数的参数描述如下:
1 选项改变所要影响的套接口s
2 选项的套接口层次level
3 要设计的选项名optname
4 指向要为新选项所设置的值的指针optval
5 选项值长度optlen

int bReuseaddr=1;

setsockopt (s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(bReuseaddr));

三。高级I/O函数

readv 读取文件写入分散的内存

writev 从分散的内存中数据拼接写入文件

sendfile 从真实文件传数据给socket。零拷贝

mmap,munmap :进程间共享内存,或者将文件映射到内存

splice 两个文件描述符直接移动数据,零拷贝,但至少有一个是管道文件

tee函数:两个管道间直接复制数据,零拷贝,tee调用后,源管道中的数据仍然可以使用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值