首页 > 编程知识 正文

套接字编程步骤,c++网络编程

时间:2023-05-04 08:36:46 阅读:156255 作者:4520

目录:

socketbindlistenconnectaccept1. socket:(1)函数原型: # includesys/types.h # includesys/socket.hintsocket (int dodoct )

因为套接字函数用于创建在APP应用层调用的套接字,所以当APP应用程序调用套接字以创建套接字时,基于APP应用层的业务类型,网络层和传输层使用的协议

内核套接字按层次抽象展示,通过提取共性的东西,可以尽量统一对外提供的接口。

在内核中抽象展示插座的定义。 例如,struct sock - struct inet_sock - struct tcp_sock从抽象到具体化

套接字函数的这三个参数实际上是具体化抽象套接字的条件,domain参数决定图中所示的第2层通信域,type决定第3层通信模式,protocol决定第4层真正的通信协议。

domain参数的几个常见值:

af _ UNIX/af _ local 3360 local communication,本地通信AF_INET : IPv4网络通信AF_INET6 : IPv6网络通信type参数的一些常规值

SOCK_STREAM :流套接字:序列化、可靠、双工、基于连接的字节流服务SOCK_DGRAM :数据报套接字:基于数据报的服务

SOCK_NONBLOCK :设置为非阻塞IO,并且functl(o_nonblock )具有相同的效果。 SOCK_CLOEXEC :与open ) o_cloexec类似,在open打开时关闭文件描述符,以防止从父过程的泄露

确定套接字支持哪种协议。 例如,如果domain=AF_INET,type=SOCK_STREAM,则内核将自动执行Protocol=IPPROTO_TCP;

domain=AF_INET,type=SOCK_DGRAM时,protocol=IPPROTO_UDP

socket(af_inet,SOCK_STREAM,0 ); 等效于//:socket(af_inet,SOCK_STREAM,IPPROTO_TCP ); socket(af_inet,SOCK_DGRAM,0 ); //和等效: socket(af_inet,SOCK_DGRAM,IPPROTO_UDP ); (3)返回值)成功时返回sockfd套接字描述符,失败时返回-1,设置errno。

常见错误:

e acces :您无权创建sockfd套接字EINVAL。 指定的协议错误2.bind:(1) bind函数原型: # includesys/socket.hint bind (int sockfd,conststructsockaddr* ) ) )。 使用案例:

struct sockaddr_in servaddr; bzero(servaddr,sizeof ) (servaddr ); servaddr.sin_family=AF_INET; servaddr.sin _ addr.s _ addr=htonl (in addr _ any ); //inet_pton(af_inet,' 192.254.1.16 ',(servaddr.sin_addr.s_addr ) ) ); servaddr.sin_port=htons(65535; bind(listenfd,(struct sockaddr* ) servaddr,sizeof ) servaddr ); )2) bind参数:套接字函数创建sockfd套接字描述符,为了进行网络通信,将套接字与端口号和IP地址相关联(端口号IP地址用于描述TCP连接的一端),在Unix上是套接字地址

服务端(客户端)的APP应用进程将自己想要绑定的IP地址和端口写入套接字地址结构等结构中传递给内核,服务端内核在接收到新的客户端连接后,将客户端的IP地址和端口传递给内核

另外,由于历史的理由,套接字地址结构在ANSI C之前被定义,因为当时的函数中没有void *那样的参数类型,所以bind那样的函数要接受IPv4、IPv6等很多类型的地址结构体时,是共同的结构因此,通用套接字地址结构应运而生。

IPv4套接字地址结构: # includenetinet/in.hstructsockadrr _ in { uint8_ tsin _ le }

n;//length of structure(16)sa_family_t sin_family;//AF_INETin_port_tsin_prot;//`16` bit TCP or UDP port numberstruct in_addr sin_addr;//`32` bit IPv4 Addresschar sin_zero[8];//unused};struct in_addr {in_addr_t s_addr;}; 通用套接字地址结构: #include <sys/socket.h>struct sockaddr {uint8_tsa_len;sa_family_tsa_family;charsa_data[14];}; 字节序转换函数:

主机字节序可能与网络字节序不相同,因此在传入地址、端口号等时需要先进行字节序转换:

#include <netinet/in.h>unit16_thtons(uint16_t val);//将16 bit位的整数从主机序转换为网络序,返回值为网络序uint32_t htonl(uint32_t val);uint16_tntohs(uint16_t val);uint32_tntohl(uint32_t val); 地址转换函数:

由于网络IP地址的表达方式有多种(ASCII字符串、网络字节序的二进制),因此需要转换。

#include <arpa/inet.h>int inet_pton(int family, const char *strptr, void *addrptr);//成功则返回1,格式无效返回0,失败返回-1const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);//成功则返回指向结果的指针,失败返回NULL (3)bind 返回值:

成功返回0,失败返回-1,并设置errno

常见的errno:

EADDRINUSE: Address already in use,所以要绑定的地址已使用 3. listen: (1)listen 函数原型: #include <sys/socket.h>int listen(int sockfd, int backlog); (2)listen 参数: backlog:

内核为一个监听套接字维护两个队列:(注意一定是监听套接字,服务端等待连接的套接字)

SYN队列:
在三次握手中,收到了客户端的第一个SYN,此时连接放入SYN队列中(未完成连接队列);ACCEPT队列:
在三次握手中,收到了客户端的第三个ACK,此时连接从SYN队列中取出,放入到ACCEPT队列中。服务端调用accept,就是从ACCEPT队列中取出一个已完成连接。 backlog到底指的是哪个队列的大小?

在《TCP/IP详解(卷一)》中这样描述:

SYN队列的大小由内核参数net.ipv4.tcp_max_syn_backlog决定(默认1000);
ACCEPT队列取 min(backlog, net.core.someconn=128)的最小值来决定。

也就是说listen函数的backlog参数是用来配置ACCEPT全连接队列的,但是ACCEPT队列同时要受另一个内核参数的限制。

(3)listen 返回值:

成功返回0,失败返回-1,并设置errno

常见的errno:

EADDRINUSE: Another socket is already listening on the same port. 另一个套接字已经在监听这个端口ENOTSOCK: The file descriptor sockfd does not refer to a socket. 传入的fd文件描述符不是套接字 4. connect: (1)connect 函数原型: #include <sys/socket.h>#include <sys/types.h>int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen); (2)connect 参数:

(3)connect 返回值:

成功返回0,失败返回-1,并设置errno

常见的errno:

EINPROGRESS: sockfd为非阻塞,且数据未就绪时connect返回(待补充)ECONNREFUSED: No-one listening on the remote address. 所连接的IP地址上没有套接字监听ETIMEOUT: Timeout while attempting connection. The server may be too busy to accept new connections. 连接超时(TCP三次握手超时,可能是服务器繁忙没有响应) 5. accept: (1)accept 函数原型: #include <sys/socket.h>int accept(int listenfd, struct sockaddr *cliaddr, socklen_t *addrlen); (2)accept 参数:

(3)accept 返回值:

成功返回非负描述符(connfd),失败返回-1,并设置errno

常见的errno:

EAGAIN or EWOULDBLOCK : The socket is marked nonblocking and no connections are present to be accepted.//accpe对应的fd被设置为非阻塞,且当前无数据可读时,将返回 AGGIN或EWOUDBLCK。

参考内容:

socket函数的domain、type、protocol解析

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。