5.1   socket地址API

大端字节序(网络序):高位在低址,低位在高址

小端字节序(主机序):低位在低址,高位在高址

判断,利用联合的特性:

 #include <iostream>
using namespace std; int main()
{
union
{
int value;
char union_bytes[ sizeof(int) ];
} test;
test.value = 0x01020304;
for(int i = ;i < ;i++)
cout<<test.union_bytes[i]<<" ";
return ;
}

输出4321就是小端,1234就是大端

JAVA虚拟机采用大端

Linux提供4个函数来完成主机字节序和网络字节序之间的转换:

 #include <netinet/in.h>
unsigned long int htonl(unsigned long int hostlong);
unsigned short int htons(unsigned short int hostshort);
unsigned long int ntohl(unsigned long int netlong);
unsigned short int ntohs(unsigned short int netshort);

这4个函数,长整型(32bit)函数通常用来转换ip地址,短整型(16bit)函数用来转换端口号,当然不限于此。

通用socket地址

 #include <bits/socket.h>
struct sockaddr
{
sa_family_t sa_family;
char sa_data[];
};

sa_family地址簇类型如下:AF_UNIX,AF_INET, AF_INET6

专用socket地址

 #include <sys/un.h>
struct sockaddr_in
{
sa_family_t sin_family;
u_int16_t sin_port;
struct in_addr sin_addr;
};
struct in_addr
{
u_int32_t s_addr;
};

实际使用中sockaddr_in需要强制转换sockaddr(sockaddr不够的补0)

ip地址转换函数

 #include <arpa/inet.h>
in_addr_t inet_addr(const char* strptr);
int inet_aton(const char* cp, struct in_addr* inp);
char* inet_ntoa(struct in_addr in);//内部使用静态变量,不可重入

inet_addr函数将用点分十进制字符串表示的ipv4地址转化为用网络字节序整数表示的ipv4地址。失败时返回INADDR_NONE。

 #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);

inet_pton将点分十进制src转化为网络字节序整数标示的ip地址存储与dst指针中  inet_ntop相反

5.2   创建socket 

socket是可读,可写,可控制,可关闭的文件描述符

 #include<sys/types.h>
#include<sys/socket.h>
int socket(int domain, int type, int protocol);

domain协议族:AF_UNIX,AF_INET, AF_INET6

type:SOCK_STREAM  SOCK_DGRAM

protocol:默认0

5.3 命名socket

将一个socket与socket地址绑定成为给socket命名,服务端通常需要命名socket,因为只有命名后客户端才知道如何连接它。客户端一般采用操作系统自动分配的socket地址

 #include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);

bind成功返回0,失败返回-1并设置errno。其中两中常见的errno是EACCES和EADDRINUSE,含义分别是:

  • EACCES:被绑定的地址是受保护的地址,仅超级用户能访问。比如普通用户将socket绑定到知名服务端口(端口号为0-1023)。
  • EADDRINUSE:被绑定的地址正在使用。如将socket绑定到一个处于TIME_WAIT状态的socket地址。

5.4 监听socket 

 #include<sys/types.h>
#include<sys/socket.h>
int listen(int sockfd, int backlog);

sockfd是被监听的socket

backlog是处于完全连接的socket的上限 ,通常监听队列中完整连接的上限比backlog值略大(一般为backlog+1)

5.5 接受连接

 #include<sys/types.h>
#include<sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockfd是被监听的socket

addr参数用来获取被接受连接的远端socket地址,长度由addrlen指出

返回一个新连接的socket,该socket唯一标识了被接受的这个连接

5.6 发起连接

 #include<sys/types.h>
#include<sys/socket.h>
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);

sockfd参数由socket系统调用返回一个socket,一旦连接建立成功sockfd就唯一标识这个连接,客户端通过读写sockfd来与服务器通信

serv_addr是服务器监听socket地址

5.7 关闭连接

 #include<unistd.h>
int close(fd);

close系统调用并非总是关闭一个连接,而是将fd的引用计数减1.只有当fd的引用计数为0时,才真正关闭连接。多进程程序中,一次fork系统调用默认将使父进程中打开的socket的引用计数加1,因此我们必须在父进程和子进程中都对该socket执行close调用才能将连接关闭。
如果无论如何都要立即终止连接(而不是将socket引用计数减1),可以使用shutdown系统调用(专为网络编程设计的)

 #include<sys/socket.h>
int shutdonw(int sockfd, int howto);

howto参数:
SHUT_RD//关闭sockfd上读的这一半。该socket接收缓冲区中的数据都被丢弃
SHUT_WR//关闭sockfd上写的这一半。发送缓冲区中的数据会在真正关闭连接之前全部发送出去,应用程序不可再对该socket文件描述符执行写操作。连接处于半关闭状态。
SHUT_RDWR//同时关闭读写。
由此可见,shutdown能够分别关闭socket上的读或写,或者都关闭。而close在关闭连接时只能将socket上的读和写同时关闭。

5.8 数据读写

tcp

 #include<sys/types.h>
#include<sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

recv成功时返回实际读取到的数据的长度,它可能小于我们期望的长度len。因此我们可能要多次调用recv,才能读取到完整的数据。recv可能返回0,这意味着通信对方已经关闭连接了。
flags参数:

udp

 #include<sys/types.h>
#include<sys/socket.h>
ssize_t recvfrom(int sockfd, void* buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addrlen);
ssize_t sendto(int sockfd, void* buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen);

recvfrome读取sockfd上的数据,buf和len分别制定读缓冲的位置和大小。因为UDP通信没有连接的概念,所以每次读取数据都要获取发送端的地址,即参数src_addr

sendto dest_addr指定接收端的socket地址

这两组函数也可用于面向连接的socket,把最后两个参数设为NULL

通用数据读写函数

 #include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags);
ssize_t sendmsg(int sockfd, struct msghdr* msg, int flags);
struct msghdr {
void* msg_name; //socket地址
socklen_t msg_namelen;
struct iovec* msg_iov;
int msg_iovlen;
void* msg_control; //指向辅助数据的起始位置
socklen_t msg_controllen;
int msg_flags; //复制函数中flsgs参数,并在调用过程中更新
};
struct iovec {
void* iov_base; //内存起始地址
size_t iov_len; //这块内存的长度
};

5.9 带外标记 

Linux内核检测到tcp紧急标志时,将通知应用程序有带外数据需要接收。内核通知应用程序带外数据到达的两种常见方式:IO复用产生的异常事件和SIGURG信号。但是,即使应用程序得到了有带外数据需要接收的通知,还需要知道带外数据在数据流中的具体位置,才能准确接收带外数据。

 #include <sys/socket.h>
int sockatmark(int sockfd);

sockatmark判断sockfd是否处于带外标记,即下一个被读取到的数据是否是带外数据。如果是,sockatmark返回1,此时我们就可以利用带MSG_OOB标志的recv调用来接收带外数据。

5.10 地址信息函数 

 #include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr* address, socklen_t* address_len);
int getpeername(int sockfd, struct sockaddr* address, socklen_t* address_len);

获取本地或远端的socket地址存储于address中

5.11 socket选项(重要)

 #include <sys/socket.h>
int getsockopt(int sockfd, int level, int option_name, void* option_value, socklen_t* restrict option_len);
int setsockopt(int sockfd, int level, int option_name, const void* option_value, socklen_t option_len);

前者用于读取socket文件描述符,后者用于设置socket文件描述符

sockfd:指定被操作的目标

level:指定要操作哪个协议选项

option_names:指定选项名字

option_value:被操作选项的值

option_len:值的长度

例子:

udp多播:

 setsockopt(sock,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop));
//加入多播组
setsockopt(sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
//退出多播组
setsockopt(sock,IPPROTO_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(mreq));

对服务器而言,有部分socket选项只能在调用listen前针对监听socket设置才有效

5.12 网络信息api 

gethostbyname  gethostbyaddr

 #include<netdb.h>
struct hostent* gethostbyname(const char* name);
struct hostent* gethostbyaddr(const void* addr, size_t len, int type);
struct hostent {
char* h_name;
char** h_aliases;
int h_addrtype;
int h_length;
char** h_addr_list;
};

获取服务信息getservbyname  getservbyport

 #include<netdb.h>
struct servent* getservbyname(const char* name, const char* proto);
struct servent* getservbyport(int port, const char* proto);
struct servent {
char* s_name;
char** s_aliases;
int s_port;
char* s_proto;
};

getaddrinfo通过主机名获取ip 通过服务获得端口

 #include<netdb.h>
int getaddrinfo(const char* hostname, const char* service,
const struct addrinfo* hints, struct addrinfo** result);
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
char* ai_canonname;
struct sockaddr* ai_addr;
struct addrinfo* ai_next;
};

getnameinfo函数通过socket地址同时获得以字符串表示的主机名和服务名

 #include<netdb.h>
int getnameinfo(const struct sockaddr* sockaddr, socklen_t addrlen, char* host, socklen_t hostlen, char* serv, socklen_t servlen, int flags);

5 Linux网络编程基础API的更多相关文章

  1. 服务器编程入门(4)Linux网络编程基础API

      问题聚焦:     这节介绍的不仅是网络编程的几个API     更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系.     这节主要介绍三个方面的内容:套接字( ...

  2. Linux 高性能服务器编程——Linux网络编程基础API

    问题聚焦:     这节介绍的不仅是网络编程的几个API     更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系.     这节主要介绍三个方面的内容:套接字(so ...

  3. Linux网络编程基础API

    第5章 Linux网络编程基础API 探讨Linux网络编程基础API与内核中TCP/IP协议族之间的关系,并未后续章节提供编程基础.从3个方面讨论Linux网络API. socket地址API.so ...

  4. linux高性能服务器编程 (五) --Linux网络编程基础api

    第五章 Linux网络编程基础api 1.主机字节序和网络字节序 字节序是指整数在内存中保存的顺序.字节序分为大端字节序.小端字节序. 大端字节序:一个整数的高位字节数据存放在内存的低地址处.低位字节 ...

  5. 第5章 Linux网络编程基础

    第5章 Linux网络编程基础 5.1 socket地址与API 一.理解字节序 主机字节序一般为小端字节序.网络字节序一般为大端字节序.当格式化的数据在两台使用了不同字节序的主机之间直接传递时,接收 ...

  6. linux 网络编程 基础

    网络编程基础 套接字编程需要指定套接字地址作为参数,不同的协议族有不同的地址结构,比如以太网其结构为sockaddr_in. 通用套接字: struct sockaddr { sa_family_t ...

  7. linux网络编程基础--(转自网络)

    转自 http://www.cnblogs.com/MyLove-Summer/p/5215287.html Linux下的网络编程指的是socket套接字编程,入门比较简单. 1. socket套接 ...

  8. Linux网络编程基础

    1. Linux网络模型 ① OSI七层模型和Linux四层模型 ② 各种协议之间的关系及在Linux模型中的位置 ③ 协议封装:各种协议处于一种层层封装的关系 (1)Ethernet (2)IP * ...

  9. linux 网络编程-基础篇01

    #Socket简介 是一个编程接口是一种特殊的文件描述符(everything in Unix is a file)并不仅限于TCPIP协议面向连接(Transmission Control Prot ...

随机推荐

  1. Codeforces Round #546 (Div. 2) ABCDE 题解

    1136A: 题意:一本书有n个章节,每个章节的分别在li到ri页,小明读完书后将书折在第k页,问还有多少章节没有读 题解:控制k在li~ri的范围内后输出n-i即可 #include <set ...

  2. hihoCoder #1582 : Territorial Dispute 凸包

    #1582 : Territorial Dispute 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 In 2333, the C++ Empire and the Ja ...

  3. Codeforces 833B The Bakery dp线段树

    B. The Bakery time limit per test 2.5 seconds memory limit per test 256 megabytes input standard inp ...

  4. isNaN与parseInt/parseFloat

    isNaN 返回一个 Boolean 值,指明提供的值是否是保留值 NaN (不是数字). NaN 即 Not a Number isNaN(numValue) 必选项 numvalue 参数为要检查 ...

  5. 使用L2正则化和平均滑动模型的LeNet-5MNIST手写数字识别模型

    使用L2正则化和平均滑动模型的LeNet-5MNIST手写数字识别模型 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献Tensorflow实战Google深度学习框架 实验平台: T ...

  6. vue 和react

    React 和 Vue 有许多相似之处,它们都有: 使用 Virtual DOM 提供了响应式 (Reactive) 和组件化 (Composable) 的视图组件. 将注意力集中保持在核心库,而将其 ...

  7. codeforces 876 C. Classroom Watch

    http://codeforces.com/contest/876/problem/C C. Classroom Watch time limit per test 1 second memory l ...

  8. 【BZOJ】2243 [SDOI2011]染色

    [算法]树链剖分+线段树 [题解] 树链剖分算法:http://www.cnblogs.com/onioncyc/p/6207462.html 定义线段树结构体有l,r,lc,rc,sum,data. ...

  9. HDU 2044 Coins

    有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行.请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数. 其中,蜂房的结构如下所示.   Input输入数据的第一行是一个整数N,表示测试实例的个数,然 ...

  10. flex实例(阮一峰)

    Flex 布局教程:实例篇   作者: 阮一峰 日期: 2015年7月14日 上一篇文章介绍了Flex布局的语法,今天介绍常见布局的Flex写法. 你会看到,不管是什么布局,Flex往往都可以几行命令 ...