Bootstrap

网络编程-TCP/IP

目录

1. TCP

2. UDP

3. TCP连接流程

4. UDP连接流程

5.函数接口

5.1 socket

5.2 bind

5.3 listen

5.4 accept

5.5 connect

5.6 recv/send

5.7 recvfrom/sendto


相同点:

同属于传输层协议

不同点:

TCP:流式套接字,面向连接的,可靠的通信

UDP:数据报套接字,无连接的,不可靠的通信

1. TCP

全双工通信、面向连接、可靠

TCP(即传输控制协议):是一种面向连接传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信)。

高可靠原因: 1. 三次握手、四次挥手

                        2. 序列号和应答机制

                        3. 超时,错误重传机制

                        4. 拥塞控制、流量控制(滑动窗口)

适用场景

适合于对传输质量要求较高的通信

在需要可靠数据传输的场合,通常使用TCP协议

MSN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议

2. UDP

全双工通信、面向无连接、不可靠

UDP(User Datagram Protocol)用户数据报协议,是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。

适用场景

发送小尺寸数据(如对DNS服务器进行IP地址查询时)

适合于广播/组播式通信中。

MSN/QQ/Skype等即时通讯软件的点对点文本通讯以及音视频通讯通常采用UDP协议

3. TCP连接流程

服务器:
   1.创建流式套接字(socket())------------------------>  有手机
   2.指定本地的网络信息(struct sockaddr_in)----------> 有号码
   3.绑定套接字(bind())------------------------------>绑定电话
   4.监听套接字(listen())---------------------------->待机
   5.链接客户端的请求(accept())---------------------->接电话
   6.接收/发送数据(recv()/send())-------------------->通话
   7.关闭套接字(close())----------------------------->挂机

客户端:
   1.创建流式套接字(socket())----------------------->有手机
   2.指定服务器的网络信息(struct sockaddr_in)------->有对方号码
   3.请求链接服务器(connect())---------------------->打电话
   4.发送/接收数据(send()/recv())------------------->通话
   5.关闭套接字(close())--------------------------- >挂机

4. UDP连接流程

服务器:

1. 创建数据报套接字 socket

2. 填充网络信息

3. 绑定 bind

4. 发送接收消息 sendto/recvfrom

5. 关闭套接字 close

客户端:

1. 创建数据报套接字 socket

2. 指定网络(服务器)信息

3. 发送接收消息 sendto/recvfrom

4. 关闭套接字 close

5.函数接口

5.1 socket

头文件:
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> 

int socket(int domain, int type, int protocol);
功能:创建套接字
参数:
   domain:协议族
         AF_UNIX, AF_LOCAL  本地通信
         AF_INET            ipv4
         AF_INET6            ipv6

  type:套接字类型
         SOCK_STREAM:流式套接字
         SOCK_DGRAM:数据报套接字
         SOCK_RAW:原始套接字

  protocol:协议 - 填0 自动匹配底层 ,根据type系统默认自动帮助匹配对应协议
         传输层:IPPROTO_TCP、IPPROTO_UDP、IPPROTO_ICMP
         网络层:htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL)

返回值:
    成功 文件描述符
    失败 -1,更新errno

5.2 bind

#include <sys/types.h>         
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:绑定服务器地址(只允许绑定本机器的网卡地址)
参数:
    socket:套接字描述符

    addr:代表的是本机的IP地址和端口,用于通信结构体 (提供的是通用结构体,需要根据选择通信方式,填充对应结构体-通信当时socket第一个参数确定)  
 
    addrlen:地址的长度,结构体大小  
 
  返回值:成功 0   失败-1,更新errno
  
 通用结构体:
  struct sockaddr {
     sa_family_t sa_family;
     char        sa_data[14];
 }

ipv4通信结构体:
struct sockaddr_in {
    sa_family_t    sin_family;
    in_port_t      sin_port;  
    struct in_addr sin_addr;  
};

struct in_addr {
    uint32_t       s_addr;    
};

本地通信结构体:
 struct sockaddr_un {
     sa_family_t sun_family;               /* AF_UNIX */
     char        sun_path[108];            /* pathname */
 };

5.3 listen

int listen(int sockfd, int backlog);
功能:监听socket连接,将主动套接字变为被动套接字
参数:
     sockfd:套接字
     backlog:同时响应客户端请求链接的最大个数,不能写0.
          不同平台可同时链接的数不同,一般写6-8个
         (队列1:保存正在连接)
         (队列2,连接上的客户端)
     返回值:成功 0   失败-1,更新errno 

5.4 accept

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
accept(sockfd,NULL,NULL);
功能:接收一个客户端的连接,它是一个阻塞接口,直到有客户端连入的时候,会退出阻塞.如果有客户端连接,则accept()函数返回,返回一个用于通信的套接字文件;

参数:
   Sockfd :套接字
   addr: 链接客户端的ip和端口号
      如果不需要关心具体是哪一个客户端,那么可以填NULL;
   addrlen:结构体的大小
     如果不需要关心具体是哪一个客户端,那么可以填NULL;

返回值: 
     成功:文件描述符; //用于通信
	 失败:-1,更新errno

5.5 connect

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
作用:客户端的socket连接服务器
参数:
    sockfd:    socket接口返回的文件描述符
    addr:    服务器的地址,帮助文档的接收在bind里,
    addrlen:    地址的长度,结构体大小

返回值:0 -1
        

第二个参数struct sockaddr *addr的解释
struct sockaddr {
   sa_family_t sa_family;   //同socket接口的domain参数
   char        sa_data[14];
}

上面的接口类型只是socket接口族为了兼容多种协议,定义的一个通用的结构体,实际编程的时候,
需要你根据具体的协议类型,使用具体协议的结构体,对于ipv4来讲,需要看ip的第7个手册(man 7 ip)
就能得到下面这个地址

struct sockaddr_in {
   sa_family_t    sin_family; /* address family: AF_INET */
   in_port_t      sin_port;   /* 端口:网络字节序 */
   struct in_addr sin_addr;   /* IP地址:网络字节序 */
};

/* Internet address. */
struct in_addr {
   uint32_t       s_addr;     /* ip地址:网络字节序 */
};

5.6 recv/send

#include <sys/types.h>
#include <sys/socket.h>

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
作用:接收网络的数据
参数:
    sockfd:文件描述符
    buf:数据的存放缓冲区
    len:buf缓冲区的最大长度
    flags:默认填0 阻塞接收
返回值:
    成功会返回实际接收到的字节个数
    失败返回-1
    如果返回0的话,代表对端退出

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
作用:发送网络的数据
参数:
    sockfd:文件描述符
    buf:数据的发送缓冲区
    len:发的缓冲区大小
    flags:默认填0
    
返回值:
    成功会返回实际发送成功的字节个数
    失败返回-1

5.7 recvfrom/sendto

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
				struct sockaddr *src_addr, socklen_t *addrlen);
功能:接收数据

参数:
	sockfd:套接字描述符
	buf:接收缓存区的首地址
	len:接收缓存区的大小
	flags:0
	src_addr:发送端的网络信息结构体的指针
	addrlen:发送端的网络信息结构体的大小的指针

返回值:
	成功接收的字节个数
	失败:-1
	0:客户端退出
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

功能:发送数据

参数:
	sockfd:套接字描述符
	buf:发送缓存区的首地址
	len:发送缓存区的大小
	flags:0
	src_addr:接收端的网络信息结构体的指针
	addrlen:接收端的网络信息结构体的大小

返回值: 
	成功发送的字节个数
	失败:-1

;