int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);功能: 接受请求,获取建立好的连接参数: sockfd:监听套接字 addr:获取客户端的ip和端口信息(ipv4套接字结构体地址) addrlen:ipv4套接字结构体的大小的地址socklen_t addrlen = sizeof(struct sockaddr);返回值:成功返回一个连接套接字,用来标识远端建立好连接的套接字,失败返回-1
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);功能: 发起请求,请求与服务器建立连接(一般用于客户端向服务端发送请求)参数: sockfd:套接字,发起连接请求的套接字addr:ipv4套接字结构体的地址 , 描述自身的相关信息 , 用来标识自身,需要自己填充,让对端知道是请求方的信息,以便进行响应addrlen:描述addr的大?。╥pv4套接字结构体的长度)返回值: 成功返回0,失败返回-1
思考一下:不知道大家是否对
accept
会有疑惑 , 已经通过
socket
创建好了一个套接字,accept又返回了一个套接字,这两个套接字有什么区别吗?UDP只有一个套接字就可以进行通信了,而TCP还需要这么多个,这是为什么?
答案是肯定有的,socket创建的套接字是用来服务端本身进行绑定的 。因为UDP是面向数据报,无连接的,所以创建好一个套接字之后直接等待数据到来即可,而TCP是面向连接 , 需要等待连接的到来,并获取连接,普通的一个套接字是不能够进行连接的监听,这时就需要用的listen来对创建好的套接字进行设置,将其设置为监听状态 , 这样这个套接字就可以不断监听连接状态,如果连接到来了,就需要通过accept获取连接 , 获取连接后返回一个值,也是套接字,这个套接字是用来描述每一个建立好的连接 , 方便维护连接和给对端进行响应,后期都是通过该套接字对客户端进行通信,也就是对客户端进行服务 。所以说,开始创建的套接字是与自身强相关的 , 用来描述自身,并且需要进行监听,所以我们也会称这个套接字叫做监听套接字,获取到的每一个连接都用一个套接字对其进行唯一性标识,方便维护与服务 。一个通俗的类比,监听套接字好比是一家饭馆拉客的,不断地去店外拉客进店,拉客进店后顾客需要享受服务 , 这时就是服务员对其进行各种服务,服务员就好比是accept返回的套接字,此时拉客的不需要关心服务员是如何服务顾客的 , 只需要继续去店外拉客进入店内就餐即可 。
基于TCP协议的套接字协议服务器整体框架封装一个类 , 来描述tcp服务端 , 成员变量包含端口号和监听套接字两个即可 , ip像udp服务端一样,绑定
INADDR_ANY
,构造函数根据传参初始化port,析构的时候关闭监听套接字即可
#define DEFAULT_PORT 8080 // 默认端口号为8080#define BACK_LOG 5 // listen的第二个参数class TcpServer{public:TcpServer(int port = DEFAULT_PORT):_port(port),_listen_sock(-1){}~TcpServer(){if (_listen_sock >= 0) close(_listen_sock);}private:int _port;int _listen_sock;};
服务端的初始化创建套接字创建套接字用到的是socket这个接口,具体介绍如下:
int socket(int domain, int type, int protocol);功能: 创建套接字参数: domain:协议家族,我们用的都是IPV4,这里会填AF_INETtype:协议类型 。可以选择SOCK_DGRAM(数据报,UDP)和SOCK_STREAM(流式服务 , TCP)protocol:协议类别,这里填写0,根据前面的参数自动推导需要那种类型返回值: 成功返回一个文件描述符,失败返回-1
代码如下:
bool TcpServerInit(){ // 创建套接字 _listen_sock = socket(AF_INET, SOCK_STREAM, 0); if (_listen_sock < 0){cerr << "socket creat fail" << endl;return false; } cout << "socket creat succes, sock: " << _listen_sock << endl;}
绑定端口号绑定端口号需要用到bind这个接口:
int bind(int sockfd, struct sockaddr *my_addr, socklen_taddrlen);参数: sockfd:套接字 my_addr:这里传一个sockaddr_in的结构体,里面记录这本地的信息:sin_family(协议家族)、sin_port(端口号)和sin_addr(地址),用来进行绑定 addrlen:第二个参数的结构体的大小返回值: 成功返回0,失败返回-1
这里端口号我们填充一个8080,协议家族填充的还是AF_INET,这里IP绑定一个字段叫INADDR_ANY(通配地址),值为0 , 表示取消对单个IP的绑定,服务器端有多个IP,如果指明绑定那个IP , 那么服务端只能够从这个IP获取数据,如果绑定INADDR_ANY,那么服务端可以接受来自本主机任意IP对该端口号发送过来的数据填充好了这个结构体,我们需要它进行强转为struct sockaddr
推荐阅读
-
华为手机怎么通过usb连接电脑上网 手机通过usb连接电脑上网
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
崩坏3周年庆累消活动自选推荐-累消活动奖励选什么读懂您就是高手
-
-
-
虎年运势2022年运势如何,属虎2022年的运势怎么样
-
鸡汤怎么炖好喝又营养 营养又好喝的三种鸡汤分享给你