Linux下的TCP套接字编程
2021/12/24 7:09:12
本文主要是介绍Linux下的TCP套接字编程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Linux下的TCP套接字编程
- 客户端
- 基本流程
- 创建socket套接字
- 设置与服务器ip和服务器端口相关的数据结构
- 连接服务器
- 服务器端
- 基本流程
- 创建socket套接字
- 设置与服务器ip和服务器端口相关的数据结构
- 绑定套接字和服务器ip及端口
- 监听
- 接受客户端连接
- 其他接口
- 获取本地和远端协议地址
- 接收数据
- 发送数据
客户端
基本流程
创建socket套接字
//函数原型 #include<sys/types.h> #include <sys/socket.h> int socket(int family, int type, int protocol); /*返回值 成功:非负描述字,即非负整数值,称为套接字。同文件描述符类似 出错:-1*/ /*参数 family:协议族,一般都是AF_INET(ipv4协议)或者PF_INET6(ipv6协议) type:套接字通信类型,一般是SOCK_STREAM(tcp)或者SOCK_DGRAM(udp) protocol:制定某个协议的特定类型,一般设置为0 */
设置与服务器ip和服务器端口相关的数据结构
#include <netinet/in.h> struct in_addr { in_addr_t s_addr; }; struct sockaddr_in { uint8_t sin_len;//地址结构长度 sa_family_t sin_family; //协议族,与socket函数第一个参数相同 in_port_t sin_port; //端口号 struct in_addr sin_addr; //IP地址 char sin_zero[8]; //填充字段 }; sockaddr_in serverAddress; //使用前要将其清零 memset(&serverAddress, 0, sizeof(sockaddr_in); //端口赋值 serverAddress.sin_port = htons(4000);//使用htons()函数是因为主机字节序列(小端)和网络字节序列(大端)不同 //服务器ip地址赋值 #include <arpa/inet.h> int inet_aton(const char* strptr, struct in_addr *addrptr);//将strptr指向的字符串,转换成32位的网络字节序二进制值,并存储在addrptr指向的结构体中 in_addr_t inet_addr(const char* strptr); //将strptr指向的字符串,转换成32位的网络字节序二进制值,将其作为返回值返回 serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1"); int inet_pton(int family, const char* strptr, void *addrptr);//addrptr:转换strptr指向的字符串,将网络字节序的二进制值,存储在addrptr指向的内存 //通常addrptr指向sockaddr_in或sockaddr_in6 inet_pton(AF_INET, strServerIP, &serverAddress.sin_addr)
连接服务器
//函数原型 #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen); connect(nClientSocket, (sockaddr*)&ServerAddress, sizeof(ServerAddress)) /* connect激发TCP的三路握手过程;仅在连接建立成功或出错时才返回 其中错误有以下几种情况: 如果客户没有收到SYN分节的响应(总共75秒,这之间需要可能需要重发若干次SYN),则errno被设置为ETIMEDOUT(等于110)。 如果对客户的SYN的响应是RST,则表明该服务器主机在该端口上没有进程在等待。errno被设置成ECONNREFUSED(等于111); 如果客户发出的SYN在中间路由器上引发一个目的地不可达ICMP错误,则如第一种情况,连续发送SYN,直到规定时间仍未收到响应,则errno被设置成EHOSTUNREACH(113)或ENETUNREACH(101)。 如果函数connect失败,则套接字不可再用,必须关闭。不能再对此套接字再调用函数connect。 */
服务器端
基本流程
创建socket套接字
同客户端
设置与服务器ip和服务器端口相关的数据结构
同客户端
ServerAddress.sin_addr.s_addr = htonl(INADDR_ANY);//设置为本地ip
绑定套接字和服务器ip及端口
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen); bind(nListenSocket, (sockaddr *)&ServerAddress, sizeof(sockaddr_in)); //返回值:成功为0,出错为-1 /* TCP服务器或客户端,都可以不调用或调用bind函数 TCP服务器通常都要调用bind函数,绑定在一个预先设置好的端口上 若TCP服务器不调用bind函数,当调用listen函数时,内核将自动分配一个端口 TCP客户端通常都不要调用bind函数,当调用connect函数时,内核自动分配一个端口 */
监听
//函数原型 #include<sys/socket.h> int listen(int sockfd, int backlog); //返回值:成功返回0,出错返回-1 //listen的第二个参数规定了内核应该为相应套接口排队的最大连接个数 /*当调用完listen函数,无论服务器是否调用accept函数(从监听队列中取出一个连接) 客户端都可以向服务器发送数据,数据将保存在已连接套接口的接收缓冲区中*/ listen(nListenSocket, nLengthOfQueueOfListen);
接受客户端连接
//函数原型 #include<sys/socket.h> int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen); //cliaddr:当accept函数返回时,内核将从已完成连接队列中,取出一个连接;并将该连接的客户端信息(协议族、IP、Port),保存在cliaddr指向的结构体中 //可以将cliaddr和addrlen设置为NULL sockaddr_in ClientAddress; socklen_t LengthOfClientAddress = sizeof(sockaddr_in); int nConnectedSocket = ::accept(nListenSocket, (sockaddr *)&ClientAddress, &LengthOfClientAddress);
其他接口
获取本地和远端协议地址
//函数原型 int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen); /*参数 sockfd:需要查询的套接字 localaddr:该函数返回时,填充该结构 addrlen:调用该函数之前,让*addrlen为localaddr指向的套接口地址结构大小;调用之后,为实际套接口地址结构大小 0:成功,-1:出错*/ //函数原型 int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen); /*返回远端的地址或端口信息(服务器调用,返回客户,客户调用返回服务器) 参数 sockfd:需要查询的套接字 peeraddr:该函数返回时,填充该结构 addrlen:调用该函数之前,让*addrlen为localaddr指向的套接口地址结构大小;调用之后,为实际套接口地址结构大小 0:成功,-1:出错*/
接收数据
#include <unistd.h> int read(int fd, char *buf, int len); /* 返回:大于0-读写字节大小;-1-出错; 调用函数read时,有如下几种情况: 套接字接收缓冲区接收到数据,返回接收到的字节数; tcp协议收到FIN数据,返回0; tcp协议收到RST数据,返回-1,同时errno为ECONNRESET; 进程阻塞过程中接收到信号,返回-1,同时errno为EINTR。*/
发送数据
#include <unistd.h> int write(int fd, char *buf, int len); /* 返回:大于0-读写字节大小;-1-出错; 调用函数write,有如下几种情况: 套接字发送缓冲区有足够空间,返回发送的字节数; tcp协议接收到RST数据,返回-1,同时errno为ECONNRESET; ; 进程阻塞过程中接收到信号,返回-1,同时errno为EINTR。*/
这篇关于Linux下的TCP套接字编程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23linux 系统宝塔查看网站访问的命令是什么?-icode9专业技术文章分享
- 2024-11-12如何创建可引导的 ESXi USB 安装介质 (macOS, Linux, Windows)
- 2024-11-08linux的 vi编辑器中搜索关键字有哪些常用的命令和技巧?-icode9专业技术文章分享
- 2024-11-08在 Linux 的 vi 或 vim 编辑器中什么命令可以直接跳到文件的结尾?-icode9专业技术文章分享
- 2024-10-22原生鸿蒙操作系统HarmonyOS NEXT(HarmonyOS 5)正式发布
- 2024-10-18操作系统入门教程:新手必看的基本操作指南
- 2024-10-18初学者必看:操作系统入门全攻略
- 2024-10-17操作系统入门教程:轻松掌握操作系统基础知识
- 2024-09-11Linux部署Scrapy学习:入门级指南
- 2024-09-11Linux部署Scrapy:入门级指南