tcp是最常用的传输层协议,面向字节流,相较于其他协议,如udp;tcp更为复杂,tcp额外提供了可靠的、有序的和错误检测功能的数据传输服务.简单点来说,tcp更复杂,数据也更可靠
本文只是介绍tcp通信的一些接口,并不具体介绍tcp协议的内容以及各种策略
服务器端
1.socket
int socket(int domain, int type, int protocol);// tcp协议对应的参数 int listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);
- 第一个参数domain 指定通信协议域,也就是下层的ip协议,常用有
AF_INET
(IPv4)、AF_INET6
(IPv6)- 第二个参数type 指定套接字类型,SOCK_STREAM代表流式套接字,tcp是面向字节流的,所以使用这个
- 第三个参数protocol 代表具体协议,0代表根据前两个选项自动推导,也可以设置为IPPROTO_TCP
- 返回值 返回一个整数,代表文件描述符,在tcp里这个文件用来进行网络监听 ,此处和udp不同,
2.bind
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);// tcp协议参数 struct sockaddr_in local; memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; // 网络层协议 local.sin_port = htons(8888); // 绑定自己的端口号 local.sin_addr.s_addr = INADDR_ANY; // 绑定目标的ip,服务器使用INADDR_ANY代表谁都可以访问 int n = ::bind(_listensockfd, (struct sockaddr *)&local, sizeof(local));
- 第一个参数是前面socket 的返回值
- 第二个参数是一个c风格的多态,tcp使用sockaddr_in*.
- 第三个参数是第二个参数指向内容的大小
- 返回值 成功0,失败-1
3.listen
int listen(int sockfd, int backlog);// tcp协议对应的参数 int n = ::listen(_listensockfd, 5);
- 第一个参数是前面socket的返回值
- 第二个参数是一个表示链接中间状态数量的整数,取决于当前服务器的性能,一般测试时给个5就可以
- 返回值 成功0,失败-1
第二个参数的具体含义
当调用listen后,tcp开始建立连接,但不能开始通信,直到调用accept函数,毫无疑问这一块一定是单线程的,效率较低;如果此时有大量客户端同时访问,服务器accept部分请求后,剩余的会因为长时间接收不到信息而退出。
对于服务器来说,与其让大量客服端建立连接后傻等者,然后超时退出,不如直接一开始就不建立连接,相当于告诉他们别来了!
listen的第二个参数代表服务器最多允许多少个客户端处于建立链接和开始通信的中间状态
4.accept
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);// tcp协议对于的参数 struct sockaddr_in client; socklen_t len = sizeof(client); int sockfd = ::accept(_listensockfd, (struct sockaddr *)&client, &len);
- 第一个参数是前面socket的返回值
- 第二个参数是一个输出型参数,代表客户端的通信协议,ip和端口
- 第三个参数是一个输入输出型参数(没见过吧,我也第一次见):本质是一个int*,输入时代表第二个参数的大小,输出时第二个参数被修改,代表新的第二个参数的大小
- 返回值是一个文件描述符,用来进行网络通信
这个函数调用时会阻塞住线程,所以一般多线程的调用
客户端
1.socket(前面有,不多解释)
2.connect()
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);// tcp协议对应的参数 struct sockaddr_in server; memset(&server, 0, sizeof(server));server.sin_family = AF_INET; server.sin_port = htons(8888); server.sin_addr.s_addr = ::inet_addr(127.0.0.1); int n = ::connect(sockfd,(struct sockaddr *)&server, sizeof(server));
- 参数和bind差不多,但底层关系不大
- 第一个参数是前面socket 的返回值
- 第二个参数是一个c风格的多态,tcp使用sockaddr_in*.
- 第三个参数是第二个参数指向内容的大小
- 返回值是一个文件描述符,用来进行网络通信
读写
得到文件描述符后可以进行读写,客户端和服务器共用一套读写函数
最简单的方法(因为tcp面向字节流,所以直接用文件的方式)
while(true){std::string message;std::getline(std::cin,message);write(sockfd,message.c_str(),message.size());char buffer[1024];n = read(sockfd,buffer,sizeof(buffer));buffer[n] = 0;std::cout << buffer << std::endl;}::close(sockfd);
专门的网络接口
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
个人制作的一些tcp小项目
linux/网络/2.tcp · 阿巴啊巴DDDD/计算机学 - 码云 - 开源中国
ok文章到这里结束了,如果能帮到你的话,可以给我点个赞赞吗