Linux网络编程(套接字编程)

socket套接字编程

  • udp协议与tcp协议区别

  • udp协议:

                 udp协议:用户数据报协议 

                 特性:无连接,不可靠,面向数据报

                 应用场景:实时性要求大于安全性(类似于短信发送)eg.视频传输

  • tcp协议:

               tcp协议:传输控制协议

               特性:面向连接,可靠传输,面向字节流

              应用场景:安全性要求大于实时性(类似于打电话)eg.文件传输

  • 客户端和服务端区别

  1. 客户端:主动发起请求的一端,也就意味着客户端必须提前知道服务端的地址信息(ip+port)因此厂商服务端地址信息一般固定而且被固定写入客户端程序
  2. 服务端:被动接收请求,提供服务的通信端
  • udp通信流程

Linux网络编程(套接字编程)_第1张图片

  • TCP通信流程

Linux网络编程(套接字编程)_第2张图片

  • TCP通信接口

 #include

int socket(int domain  ,int type  ,int protocal)

  1. domain: 地址域类型        一般使用AF_INET(表示ipv4地址结构,采用ipv4通信)
  2. type:套接字类型   (1)SOCK_STREAM:  流式套接字  (可连接,可靠, 供TCP使用)            (2) SOCK_DGRAM:数据报套接字(不连接,不可靠,供UDP使用)
  3. protocal:协议   IPPROTO_TCP  -6    IPPROTO_UDP   -17(或0 默认协议,根据套接字类型自动配置协议)
  4. 返回值:返回一个文件描述符(操作句柄)    失败-1

(2)为套接字绑定地址信息

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

  1. sockfd:创建套接字返回的操作句柄
  2. addr:当前绑定的地址信息     通过获取到地址域进行区分
  3. addrlen:地址信息长度
  4. 返回值;成功0  失败-1

(3)开始监听

int listen(int sockfd,int backlog)

  1. sockfd:创建套接字返回的操作句柄
  2. backlog:服务端能够在同一时间处理的最大连接数,将连接的socket放在已完成连接队列中      已完成连接队列的节点数量=backlog+1

(4)客户端发送连接请求

int connect(int sockfd ,struct sockaddr * srvaddr  ,socklen_t len)

  1. sockfd:创建套接字返回的操作句柄
  2. 服务端地址信息
  3. 服务端地址长度
  4. 返回值:失败-1,成功0

(5)服务端获取新建连接

int accept(int sockfd ,struct sockaddr *ciladdr,socklen_t *addrlen)

  1. sockfd:监听套接字(服务端最早创建的套接字)只用于获取新建连接
  2. ciladdr:新的连接的服务端地址信息
  3. addrlen:输入输出参数,指定地址信息长度,以及返回实际长度
  4. 返回值:新建连接套接字的操作句柄,后续与客户端服务通过此操作句柄完成

(6)发送数据(TCP通信因为新建socket结构中已经包含完整五元组,不需要指定地址

ssize_t send(int sockfd,  void* data,  int len,   int flag)

  1. sockfd:创建套接字返回的操作句柄
  2. data:发送数据空间首地址
  3. len:发送数据长度
  4. flag:标志位 默认0 -  阻塞发送(没有发送数据则一直等待发送数据到来)
  5. 返回值:成功返回实际发送的数据长度   失败-1,连接断开,继续send会触发异常

​​​​​​​​​​​​​​(7)接收数据

ssize_t recv(int sockfd,  void* buf,   int len,   int flag)

  1. sockfd:创建套接字返回的操作句柄
  2. buf:空间地址,用于存放数据
  3. len:接受数据长度
  4. flag:标志位 默认0 -  阻塞接收(没有接收到数据则一直等待接收)
  5. 返回值:返回实际接收到的数据长度   失败-1,连接断开返回0,此时无法通信​​​​​​​

(8)关闭套接字

int close(int sockfd)

​​​​​​​代码测试:

(1)封装tcpsocket类,实例化类对象通过接口传参调用更加方便

Linux网络编程(套接字编程)_第3张图片

Linux网络编程(套接字编程)_第4张图片

Linux网络编程(套接字编程)_第5张图片

Linux网络编程(套接字编程)_第6张图片

(2)服务端

Linux网络编程(套接字编程)_第7张图片

Linux网络编程(套接字编程)_第8张图片

(3)客户端

Linux网络编程(套接字编程)_第9张图片

Linux网络编程(套接字编程)_第10张图片

Linux网络编程(套接字编程)_第11张图片Linux网络编程(套接字编程)_第12张图片

上述结果发现问题:服务端流程发生阻塞,只有新创建客户端才会重新唤醒一次服务端,当前服务端不知道什么时候有新的连接到来,什么时候有数据到来,固定流程调用接口会造成阻塞

原因分析:

accept接口,recv接口以及send接口都是阻塞接口,任意一个接口调用都有可能导致服务端阻塞

解决方案:

多执行流并发处理:为每一个客户端都创建一个执行流负责与客户端通信

优点:

  1. 主线程卡在获取新建连接这,但不会影响客户端的通信
  2. 某个客户端通信阻塞,也不会影响主线程以及其他线程
  • 多线程:普通线程与主线程数据共享,指定入口函数执行

Linux网络编程(套接字编程)_第13张图片

Linux网络编程(套接字编程)_第14张图片

Linux网络编程(套接字编程)_第15张图片Linux网络编程(套接字编程)_第16张图片

注意:主线程不能随意释放套接字,因为资源共享,一旦释放其他线程将无法再使用套接字

  • 多进程:子进程复制父进程,但数据各自独有

​​​​​​​Linux网络编程(套接字编程)_第17张图片

Linux网络编程(套接字编程)_第18张图片

Linux网络编程(套接字编程)_第19张图片

Linux网络编程(套接字编程)_第20张图片Linux网络编程(套接字编程)_第21张图片

注意:

  1. 僵尸进程的处理,signal子进程发送信号给父进程  进行忽略处理
  2. 父子进程各自数据独有,父进程不会使用新建套接字,因此子进程创建之后父进程将其释放掉,否则会造成资源泄漏
  • UDP通信接口

(1)创建套接字    
 #include

int socket(int domain  ,int type  ,int protocal)

  1. domain: 地址域类型        一般使用AF_INET(表示ipv4地址结构,采用ipv4通信)
  2. type:套接字类型   (1)SOCK_STREAM:  流式套接字  (可连接,可靠, 供TCP使用)            (2) SOCK_DGRAM:数据报套接字(不连接,不可靠,供UDP使用)
  3. protocal:协议   IPPROTO_TCP  -6    IPPROTO_UDP   -17(或0 默认协议,根据套接字类型自动配置协议)
  4. 返回值:返回一个文件描述符(操作句柄)    失败-1

(2)为套接字绑定地址信息

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

  1. sockfd:创建套接字返回的操作句柄
  2. addr:当前绑定的地址信息     通过获取到地址域进行区分
  3. addrlen:地址信息长度
  4. 返回值;成功0  失败-1

(3)接受数据

ssize_t recvfrom(int sockfd,  void* buf,   int len,   int flag,   struct sockaddr* srcaddr,    socklen_t addrlen)

  1. sockfd:创建套接字返回的操作句柄
  2. buf:空间地址,用于存放数据
  3. len:接受数据长度
  4. flag:标志位 默认0 -  阻塞接收(没有接收到数据则一直等待接收)
  5. srcaddr:本条数据源端地址信息
  6. addrlen:输入输出参数 -指定要接收多长的地址结构,并且返回实际接收到的地址长度
  7. 返回值:返回实际接收到的数据长度   失败-1

(4)发送数据

ssize_t sendto(int sockfd,  void* data,  int len,   int flag,  struct sockaddr* peeraddr,    socklen_t addrlen)

  1. sockfd:创建套接字返回的操作句柄
  2. data:发送数据空间首地址
  3. len:发送数据长度
  4. flag:标志位 默认0 -  阻塞发送(没有发送数据则一直等待发送数据到来)
  5. peeraddr:对端地址信息
  6. addrlen:输入输出参数 -指定要发送多长的地址结构,并且返回实际发送的地址长度
  7. 返回值:返回实际发送的数据长度   失败-1

(5)关闭套接字

int close(int sockfd)

(6)字节序转换接口

#include

      uint32_t htonl(uint32_t hostlong);     32位数据主机到网络字节序转换

       uint16_t htons(uint16_t hostshort);  16位数据主机到网络字节序转换

       uint32_t ntohl(uint32_t netlong);       32位数据网络到主机字节序转换

       uint16_t ntohs(uint16_t netshort);    16位数据网络到主机字节序转换

注:port端口转换使用s    ip地址转换用l

(7)IP地址转换接口

in_addr_t inet_addr(const char* cp)         将字符串点分十进制ip地址转换为整型网络字节序ip地址   192.168.2.2  ->   0xc0a80202

char *inet_ntoa(struct in_addr  in)            将整型网络字节序ip地址转换为字符串点分十进制ip地址   in.s_addr=0xc0a80202   ->   192.168.2.2

代码测试:

(1)封装udpsocket类,实例化类对象通过接口传参调用更加方便

​​​​​​​Linux网络编程(套接字编程)_第22张图片

Linux网络编程(套接字编程)_第23张图片

Linux网络编程(套接字编程)_第24张图片

(2)服务端

Linux网络编程(套接字编程)_第25张图片

Linux网络编程(套接字编程)_第26张图片

(3)客户端

Linux网络编程(套接字编程)_第27张图片

Linux网络编程(套接字编程)_第28张图片

  • 查看网络状态信息:

netstat

  • -a或--all 显示所有连线中的Socket查看所有
# netstat -a
  • -A<网络类型>或--<网络类型> 列出该网络类型连线中的相关地址。
  • -c或--continuous 持续列出网络状态。
  • -C或--cache 显示路由器配置的快取信息。
  • -e或--extend 显示网络其他相关信息。
  • -F或--fib 显示路由缓存。
  • -g或--groups 显示多重广播功能群组组员名单。
  • -h或--help 在线帮助。
  • -i或--interfaces 显示网络界面信息表单。
  • -l或--listening 显示监控中的服务器的Socket。
  • -M或--masquerade 显示伪装的网络连线。
  • -n或--numeric 直接使用IP地址,而不通过域名服务器,不以服务名称显示
# netstat -an
  • -N或--netlink或--symbolic 显示网络硬件外围设备的符号连接名称。
  • -o或--timers 显示计时器。
  • -p或--programs 显示正在使用Socket的程序识别码和程序名称。查看当前网络状态对应的进程
# netstat -ap
  • -r或--route 显示Routing Table。
  • -s或--statistics 显示网络工作信息统计表。
  • -t或--tcp 显示TCP传输协议的连线状况。
# netstat -at
  • -u或--udp 显示UDP传输协议的连线状况。
# netstat -au
  • -v或--verbose 显示指令执行过程。
  • -V或--version 显示版本信息。
  • -w或--raw 显示RAW传输协议的连线状况。
  • -x或--unix 此参数的效果和指定"-A unix"参数相同。
  • --ip或--inet 此参数的效果和指定"-A inet"参数相同。

你可能感兴趣的:(网络编程)