Linux网络编程

  • C++
  • 后端开发
  • TCP/IP通信
  • Socket

PC间的TCP/IP、UDP网络通信是互联网的一大关键技术,关于TCP/IP以及UDP的技术在其他文章中已经介绍过,本文将聚焦如何通过Linux的接口实现多台PC间的最简单的通信。

常用API函数

socket

int socket(int domain, int type, int protocol);
  • domain表示协议族,可选AF_INET/PF_INET,表示采用IPv4,AF_INET6/PF_INET6表示IPv6,PF_UNIX表示UNIX本地协议族
  • type表示服务类型,可选SOCK_STREAM为TCP协议,SOCK_DGRAM为UDP协议
  • protocol,一般取0即可
  • 成功返回0,失败返回-1并设置errno

bind

int bind(sockfd, const struct sockaddr* my_addr, socket_t addrlen);
  • sockfd是socket()函数的返回值
  • my_addr是服务端地址
  • addrlen是储存服务端地址的变量的长度sizeof
  • 成功返回0,失败返回-1并设置errno

listen

int listen(int sockfd, int backlog);
  • sockfd与上面一致
  • backlog最大监听队列长度,若监听队列超过backlog,服务器将不受理新的客户连接,客户端会受到ECONNREFUSED信息

accept

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • sockfd与上面一致
  • addr储存建立连接的客户端的ip地址,传入的实际参数通常是一个新建sockaddr_in结构体,并且初始化为0
  • addrlen为addr的长度sizeof
  • 成功会返回一个新的socket,它用于后续真正的信息传送与接收

connect

int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
  • sockfd是在客户端创建的socket
  • serv_addr为服务端地址
  • addrlen为长度sizeof
  • 成功返回-,错误返回-1并设置errno,常见的errno是ECONNREFUSED和ETIMEOUT,其含义如下:
    • ECONNREFUSED表示端口不存在,连接被拒绝
    • ETIMEOUT表示连接超时

recv

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • sockfd为建立连接后的sock,对于服务端是accept返回的socket,对于客户端则是唯一建立的那个socket
  • buf,存放数据的缓存,事先建立,作为实参传入
  • len,期望的长度,实际接受的长度<=期望的长度
  • flag一般设置为0即可,设置为MSG_OOB为发送紧急数据(带外数据)
  • 成功返回实际读取到的数据的长度,失败返回-1并设置 errno

send

ssize_t recv(int sockfd, const void *buf, size_t len, int flags);
  • 和revc基本一致

recvfrom和sendto

recv和send是使用与TCP的接口,recvfrom和sendto是适用于UDP的接口

ssize_t recvfrom(int sockfd, void* buf, sieze_t len, int flags, struct sockaddr* src_addr, socklen_t* addrlen);

ssize_t recvfrom(int sockfd, void* buf, sieze_t len, int flags, struct sockaddr* dest_addr, socklen_t* addrlen);

多了两个参数:

  • src_addr或是dest_addr,表示所要发送的地址或所要接收的地址,因为UDP不是面向连接的,所以每次传送或接受信息都要指定地址
  • addrlen长度sizeof

close

int close(int fd);
  • fd是待关闭的socket
  • 并非立刻关闭,而是将fd的引用计数减1,只有fd的引用计数为0时,才真正关闭
  • 非要立刻关闭可以用
int shutdown(int sockfd, int howto)
  • howto可选SHUT_RD关闭读的一半,SHUT_WR关闭写的一半,SHUT_RDWR同时关闭读写

hello-world示例

环境说明

一共设置了三台PC,腾讯云的一台centos 7服务器作为服务端,本地在Virtual Box开启两台ubuntu18.04虚拟机作为客户端。

端口开放设置

ubuntu18.04默认防火墙ufw一般不会开启,如果启用了,需要增添规则开放通信端口

腾讯云的centos 7服务器的端口设置需要注意两点:

  • 需要在腾讯云控制台的安全组设置中开放需要通信端口,不过一般默认是全开放,为了安全可以全关闭后只开放特定端口
  • centos 7 默认采用iptables防火墙,对于iptables防火墙的具体介绍打算在新开一个坑进行介绍,这里只做简单说明。服务端准备采用3400端口进行通信,则需要
iptables -I INPUT 2 -p tcp --dport 3400 -j ACCEPT 
service iptables save
service iptables restart

第一行指令:表示在规则链开头第二条的位置新增一个针对流入信息的规则,该规则接受3400端口的TCP应用服务。第二条指令对规则进行保存,否则重启服务或重启服务器会失效,第三条重启服务(好像不一定要重启服务)

关键代码

[]: https://github.com/zhangxixi0904/Cpp-Network.git “Linux网络编程的hello-world”

运行效果

在服务端运行

./tcp_net_server 172.0.5.171 3400 # 172.0.5.171是腾讯云的内网地址

在客户端分别运行

./tcp_net_client 服务端外网ip 3400

客户端显示

服务端显示

参考文献

  1. https://www.cnblogs.com/jfyl1573/p/6476607.html

  2. Linux高性能服务器编程 游双

  3. https://www.cnblogs.com/bazingafraser/p/8507602.html

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~

支付宝
微信