Linux应用程序9--linux网络编程

1 网络通信基础

1.1 TCP/IP协议族

2 网络框架

3 TCP

4 Socket

4.1 Socket概述

  socket是在应用层和传输层之间的一个抽象层,他把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用,以实现进程在网络中通信。

4.2 API详解

4.2.1  socket():创建socket文件描述符

  为一个socket数据结构分配存储空间,成功时,返回一个用于监听的socket描述符。

所需头文件 #include <sys/types.h> 
#include <sys/socket.h>
函数原型

int socket(int domain, int type, int protocol);

 输入值    
domain
 协议族
AF_UNIX/AF_LOCAL:Unix域协议
AF_INET:IPv4
AF_INET6:IPv6
  type SOCKET_STREAM:TCP
SOCKET_DGRAM:UDP
SOCKET_RAW:提供传输层以下的协议,可以访问内部网络接口,例如接收和发送ICMP报文
protocol 0,系统会根据type自动选择默认协议类型
当type=SOCKET_RAW时需要设置此值说明协议类型
返回值 -1,失败,失败原因存在于error中
!=-1, 成功, 监听的socket描述符

 4.2.2 bind():将一个本地协议地址与监听socket文件描述符关联 

所需头文件 #include <sys/types.h> 
#include <sys/socket.h>
函数原型

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

 输入值     sockfd 要关联的socket文件描述符
addr 指向sockaddr,包含IP地址和端口信息的结构体
addrlen sockaddr结构的大小,可设置sizeof(struct sockaddr)
返回值 -1,失败,失败原因存在于error中
0 , 成功

 4.4.3 listen() 实施监听服务

所需头文件 #include <sys/types.h> 
#include <sys/socket.h>
函数原型

int listen(int sockfd, int backlog);

 输入值     sockfd 要监听的socket文件描述符
backlog 套接字排队的最大连接个数
返回值 -1,失败,失败原因存在于error中
0 , 成功, 

4.4.4 accept()阻塞等待客户端接入 

  accept()函数仅被TCP类型的服务器程序调用,将从连接请求队列中获得连接信息,创建新的套接字,并返回该套接字的文件描述符,客户端可以通过这个描述符与服务器通信。

  通常我们把accept()第一个参数成为监听套接字(listening socket),把accept()功能返回值成为已连接套接字(connected socket)。

所需头文件 #include <sys/types.h> 
#include <sys/socket.h>
函数原型

int accept(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

 输入值     sockfd 要关联的监听socket文件描述符
addr 指向sockaddr,包含IP地址和端口信息的结构体
addrlen sockaddr结构的大小,可设置sizeof(struct sockaddr)
返回值 -1,失败,失败原因存在于error中
成功,已连接的socket描述符

4.4.5 connect()客户端调用来与服务器建立连接

所需头文件 #include <sys/types.h> 
#include <sys/socket.h>
函数原型

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

 输入值     sockfd 要关联的监听socket文件描述符
addr 指向sockaddr,包含IP地址和端口信息的结构体
addrlen sockaddr结构的大小,可设置sizeof(struct sockaddr)
返回值 -1,失败,失败原因存在于error中
0 , 成功

4.4.6 close()关闭连接的socket文件描述符

所需头文件 #include <unistd.h> 
函数原型

int close(int sockfd)

 输入值     sockfd 要关联的socket文件描述符
返回值 -1,失败,失败原因存在于error中
0 , 成功

 4.4.7 shutdown()终止socket通信

所需头文件
#include <sys/socket.h>
函数原型

int shutdown(int s, int how)

 输入值     sockfd 要关联的socket文件描述符
how 0(SHUT_RD):关闭socket连接的读这一半,不再接收套接字中的数据且现留在收缓冲区的数据作废
1(SHUT_WR):关闭socket连接的写这一半(半关闭),但留在套接字发送缓冲区中的数据都会被发送,后跟TCP连接终止序列,不管访问计数是否大于0,此后将不能再执行对套接字的任何写操作
2(SHUT_RDWR):socket连接的读、写都关闭
返回值 -1,失败,失败原因存在于error中
0 , 成功

 4.4.8 send()TCP类型数据发送

所需头文件 #include <sys/types.h> 
#include <sys/socket.h>
函数原型

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

 输入值     sockfd 要关联的socket文件描述符
addr 指向sockaddr,包含IP地址和端口信息的结构体
addrlen sockaddr结构的大小,可设置sizeof(struct sockaddr)
返回值 -1,失败,失败原因存在于error中
0 , 成功

4.4.9 recv()TCP类型数据接收

所需头文件 #include <sys/types.h> 
#include <sys/socket.h>
函数原型

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

 输入值     sockfd 要关联的socket文件描述符
*buf 接收缓冲区地址
len 接收缓冲区数据长度(按字节计算)
flags 0
返回值 -1,失败,失败原因存在于error中
!=-1 , 返回接收到的数据字节数

4.4.10 sendto()UDP类型数据发送

4.4.11 recvfrom()UDP类型数据接收

4.2.12 htonl()、htons()、ntohl()、ntohs()

网络字节序与本地字节序互相转换,规定网络字节序一律是大端模式,h——本机字节序(大端或者小端),n——网络字节序(大端)

#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);  //本机字节序转换成网络字节序
uint16_t htons(uint16_t hostshort);  //本机字节序转换成网络字节序 
uint32_t ntohl(uint32_t netlong);  //网络字节序转换成本机字节序 
uint16_t ntohs(uint16_t netshort);  //网络字节序转换成本机字节序

示例:

uint32_t addr=0x12345678, result=0; 
printf("%#x,    %#x
", addr, htonl(addr));

结果:0x78563412

4.2.11 inet_addr()

in_addr_t inet_addr(const char *cp);  //将一个字符串形式的点分十进制IP地址转换为32位二进制网络字节序

示例:

addr = inet_addr(“192.168.0.11”);    //网络字节序:规定使用大端模式
printf("addr=%#X
", addr);

结果:addr=0XB00A8C0

 4.2.12 inet_ntoa()、inet_aton()

int inet_aton(const char *cp, struct in_addr *inp);
char *inet_ntoa(struct in_addr in);

4.2.13 inet_ntop()、inet_pton()

  对于IPv4地址和IPv6地址都适用。

#include <arpa/inet.h>
/*将数值格式转化为点分十进制的ip地址格式*/ 
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);  //返回值:1,成功; 0,输入无效; -1,出错
/*点分十进制IP地址转换为用于网络传输的数值格式*/
 int inet_pton(int af, const char *src, void *dst);  //返回值:NULL,出错

示例:

#include    <stdio.h>
#include    <arpa/inet.h>
int main(void)
{
    /*1. inet_pton转换:点分十进制 转 网络数值格式*/
    struct in_addr addr;
    int ret=0;
    ret = inet_pton(AF_INET, "192.168.0.11", &addr);
    if(ret != 1){
        printf("inet_pton error
");
        return -1;
    }
    printf("addr=%#X.
", addr.s_addr);

    /*2. inet_ntop转换:网络数值格式 转 点分十进制*/
    char buf[50]={0};
    const char *p_ret=NULL;
    addr.s_addr = 0xB00A8C0;
    p_ret = inet_ntop(AF_INET, &addr, buf, sizeof(buf));
    if(p_ret == NULL){
        printf("inet_pton error
");
        return -1;
    }
    printf("addr=%s.
", buf);
}

结果:addr=0XB00A8C0.

   addr=192.168.0.11.

4.2.14 sockaddr和sockaddr_in

 

 sinport和sin_addr都必须是网络字节序(NBO)。

sockaddr缺陷是把sin_port和sin_addr混在一起放在了sa_data[14]里了;

两者长度都是16个字节,因此可以互相转换;

sockaddr常用于bind, connect, recvfrom, sendto等函数的参数

4.3 实例

原文地址:https://www.cnblogs.com/Mike2019/p/12091077.html