tcp的接口
tcp的详细细节后面讲解,先来用它的一些接口实现1个简单的通信。下面来看它的一套接口
socket
功能:socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符;应用程序可以像读写文件一样用read/write在网络上收发数据;
函数原型:
int socket(int domain, int type, int protocol);
参数说明:
- domain:协议域又称协议家族,协议族决定了socket的地址类型,跟udp的一样,用IPv4还是AF_INET
- type:套接字类别,有流式套接字和数据报套接字,tcp用的是面向流的传输协议,参数为SOCK_STREAM
- protocol:协议指定与套接字一起使用的特定协议,指定为0即可
返回值:
成功则返回socket文件描述符,错误返回-1.
socket接口在上一篇的udp中已经有了,这里不做多余的讲解。
bind
服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后就可以向服务器发起连接; 服务器需要调用bind绑定一个固定的网络地址和端口号.
函数原型:
int bind(int socket, const struct sockaddr *address,socklen_t address_len);
参数说明:
- socket:需要绑定的socket
- addr:存放了服务端用于通信的地址和端口。
- addrlen:表示addr结构体的大小。
返回值:
- 成功返回0,失败返回-1
前面的这2个接口的使用跟udp是一样的。
listen监听
listen声明sockfd处于监听状态, 并且最多允许有backlog个客户端处于连接等待状态, 如果接收到更多
的连接请求就忽略, 这里设置不会太大(一般是5)。udp完成bind后就可以接收和发送信息了,tcp在这里就跟它不同了。为什么要监听呢?因为服务器要知道从客户端发来了请求。
就像在公司的食堂吃饭一样,我们上面时候去都能吃到饭,因为食堂的打饭人员一看到人来就知道有人来吃饭了。这个打饭人员就是处于监听状态,我们吃饭就是客户端的请求。
函数原型:
int listen(int sockfd, int backlog);
参数说明:
- sockfd:监听的套接字
- backlog:最多允许有多个客户端处于连接等待状态
返回值:成功返回0,失败返回-1
accept
服务器需要接收客户端的请求,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。
函数原型:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数说明:
- sockfd:要连接的套接字
- addr:是一个传出参数,accept()返回时传出客户端的地址和端口号;
- addrlen:参数是一个传入传出参数(value-result argument), 传入的是调用者提供的, 缓冲区addr的长度以避免缓冲区溢出问题, 传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)
返回值:(重点理解返回值)
成功返回新的套接字,失败返回-1
为什么返回1个套接字?
来看个例子:
这个accept的返回值就是这个服务员,sockfd就是这个拉客的,吃饭的人就是客户端发来的请求。
这个拉客的把人带给服务员后,她有继续出去拉客了。sockfd这个套接字继续拉客也就是继续从底层获取客户端的链接,服务员专门处理链接也就是返回的这个套接字,专门处理和用户沟通。
connect
我们的客户端需要调用connet来连接服务器。
函数原型:
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数说明:
connect和bind的参数形式一致, 区别在于bind的参数是自己的地址, 而connect的参数是对方的地址;
connect()成功返回0,出错返回-1
recv
功能接收数据。
函数原型:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数说明:
- sockfd:指定接收端套接字描述符
- buf:指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;
- len:指明buf的长度
- flags:参数一般置0
返回值:
成功则返回读出来的大小,失败返回-1.
send
功能发送信息,函数原型
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
参数说明:
- sockfd:指定发送端套接字描述符
- buf:指明一个存放应用程序要发送数据的缓冲区;
- len:指明实际要发送的数据的字节数;
- flags:参数一般置0。
单进程版tcp通信
下面来利用上面的接口来写个简单服务器和客户端来实现通信,首先是单进程版的。
服务器
整体逻辑:文章来源:https://www.toymoban.com/news/detail-429233.html
- 首先初始化服务器,初始化服务器包括:先创建套接字,创建好后开始绑定,若绑定失败,则直接退出进程。绑定好后开始监听套接字,监听失败也直接退出。
- 启动服务器:监听成功后,先接收客户端发来的信息,再给客户端发送echo server服务器。
tcpServer.hpp文章来源地址https://www.toymoban.com/news/detail-429233.html
1 #pragma once
2 #include<iostream>
3 #include<cstdio>
4 #include<stdlib.h>
5 #include<cstring>
6 #include<unistd.h>
7 #include<sys/types.h>
8 #include<sys/socket.h>
9 #include<arpa/inet.h>
10 #include<netinet/in.h>
11 #define BACKLOG 5
12 class tcpServer
13 {
14 private:
15 int port;
16 int lsock;
17 public:
18 tcpServer(int _port = 8080)
19 :port(_port)
20 ,lsock(-1)
21 {
}
22 void initServer()
23 {
24 lsock = socket(AF_INET,SOCK_STREAM,0);
25 struct sockaddr_in local;
26 local.sin_family = AF_INET;//IPv4
27 local.sin_port = htons(port);//端口号,主机序列转成网络序列
28 local.sin_addr.s_addr = INADDR_ANY;//ip地址
29
30 //开始绑定
31 if(bind(lsock,(struct sockaddr*)&local
到了这里,关于socket实现tcp通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!