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. JAVA实现Excel批量导入

    一.模板下载: 先将模板放在项目WebRoot下的download文件夹下: /** * @Title: downloadFile * @Description: 模板下载 (网络地址) * @par ...

  2. opencv2 直方图之calchist函数使用(转)

    OpenCV提供了calcHist函数来计算图像直方图. 其中C++的函数原型如下:void calcHist(const Mat* arrays, int narrays, const int* c ...

  3. EA画时序图初试

    1.步骤: 1. 新建一个项目: 2. Use Case Model右键-->添加图-->左边选择UML Behavioral,右边选择Sequence: 3. 选择工具栏中的工具,点击工 ...

  4. Nginx基本功能极速入门

    http://xxgblog.com/2015/05/17/nginx-start/ 本文主要介绍一些Nginx的最基本功能以及简单配置,但不包括Nginx的安装部署以及实现原理.废话不多,直接开始. ...

  5. 000. 规范类的设计(ing)

    1.变量命名规范 变量命名有许多约定俗成的规范,下面的这些规范能有效提高程序的可读性: 标识符要能体现实际含义(顾名思义). 变量名一般用小写字母,如index,不要使用Index或INDEX. 用户 ...

  6. ACE服务端编程2:ACE跨平台之数据类型和宽字符

    ACE网络库的主要优势之一就是跨平台,ACE提供了操作系统API和编译器级别的跨平台解决方法,使开发人员不用再去关心操作系统和编译器的差异,但因此也带来了ACE的复杂性. ACE网络库的组织结构主要分 ...

  7. 【Docker】docker 入门以及一些常用指令

    概述 Docker是一款针对程序开发人员和系统管理员来开发.部署.运行应用的一款虚拟化平台.Docker 可以让你像使用集装箱一样快速的组合成应用,并且可以像运输标准集装箱一样,尽可能的屏蔽代码层面的 ...

  8. CF760 D Travel Card 简单DP

    link 题意:乘车,有3种票 1.20块坐1站 2.坐90分钟,50块 3.坐1440分钟,120块 现给出到达每个站的时间,问最优策略 思路: 简单DP,限定条件的3个转移方向,取最小的那个就行了 ...

  9. Redis实战(五)CentOS 7上搭建Redis集群

    高可用Redis(十二):Redis Cluster https://www.cnblogs.com/renpingsheng/p/9862485.html https://www.cnblogs.c ...

  10. CSS与HTML结合

    CSS与HTML结合的4中方式: 1.每个HTML标签都有style属性 2.当页面中有多个标签具有相同样式时,可定义style标签封装样式以复用 <style type=”text/css”& ...