欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

accept函数_基础套接字函数入门1

发布时间:2025/3/21 编程问答 31 豆豆
生活随笔 收集整理的这篇文章主要介绍了 accept函数_基础套接字函数入门1 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

想不想自己写一个简单的QQ?想不想自己写一个聊天室?想不想知道2000年的人是如何上网的?本节讲解一些基础的网络函数,带你看看,编写一个完整的TCP客户端、服务端需要掌握哪些函数?之后,我们要开发自己的QQ。

1 socket函数

// sys/socket.h /* 使用协议__protocol在域__domain中创建一个__type类型的新套接字。 如果__protocol为零,则自动选择一个。 返回新套接字的文件描述符,或者返回-1表示错误。 */ extern int socket (int __domain, int __type, int __protocol) __THROW;
  • __domain:即family,AF_INETIPv4协议,AF_INET6IPv6协议
  • __type:SOCK_STREAM字节流套接字,SOCK_DGRAM数据报套接字,SOCK_RAW原始套接字
  • __protocol:IPPROTO_TCPTCP传输协议,IPPROTO_UDPUDP传输协议

socket函数在成功时返回一个小的非负整数值,它与文件描述符类似,我们把它称为套接字描述符(socket descriptor),简称socketfd。

AF_前缀表示地址族,PF_前缀表示协议族 ,因为历史上曾想让一个协议族(PF)支持多个地址族(AF),用PF来创建套接字,用AF来创建套接字地址结构,然而就只是想想,没有实现。现在AF和PF的值是相等的。

// bits/socket.h /* Protocol families. */ #define PF_INET 2 /* IP protocol family. */ #define PF_INET6 10 /* IP version 6. */ /* Address families. */ #define AF_INET PF_INET #define AF_INET6 PF_INET6

2 connect函数

// sys/socket.h #define __CONST_SOCKADDR_ARG const struct sockaddr * extern int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
  • __fd:socket函数返回的套接字描述符
  • __addr:指向套接字结构地址的指针
  • __len:该套接字的大小

TCP客户用connect函数和TCP服务器建立连接。客户在调用connect函数前可以不调用bind函数,因为如果有需要,内核会确定本机IP地址,并选择一个临时端口作为源端口。

3 bind函数

// sys/socket.h /* 把一个本地协议地址赋值给一个套接字 */ #define __CONST_SOCKADDR_ARG const struct sockaddr * extern int bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len) __THROW;
  • 对于IPv4来说,协议地址是32位的IPv4地址和16位的端口号组合。
  • 对于IPv6来说,协议地址是128位的IPv6地址和16位的端口号组合。

绑定操作涉及3个对象:套接字,地址和端口。其中套接字是捆绑的主体,地址和端口是捆绑的客体。在套接字上绑定地址和端口表示:该地址和端口已经被套接字使用。

  • 如果指定端口号为0,那么内核在bind被调用的时候选择一个临时端口。
  • 如果指定IP地址是通配地址,那么内核将等到套接字已连接(TCP)或在套接字上发出数据报(UDP)时才选择一个本地IP地址。

对于IPv4来说,通配地址是0(INADDR_ANY),如果让内核帮套接字选择一个端口,那么必须注意,bind函数并不返回所选择的端口号。因为bind函数的_addr参数有const限定词,它无法返回所选的值。为了拿到内核选择的临时端口,必须调用getsockname函数来返回协议地址。

4 listen函数

// sys/socket.h extern int listen (int __fd, int __n) __THROW;

listen函数仅有TCP服务器调用,它做两件事:

  • 当socket函数创建一个套接字时,默认是主动套接字,listen函数将它变成被动套接字,指示内核应接受指向该套接字的连接请求。调用listen将导致套接字从CLOSED状态转换到LISTEN状态。
  • 第二个参数__n规定了内核应该为相应套接字排队的最大连接个数。内核为任意一个监听套接字维护两个队列,一个叫未完成连接队列,一个叫已完成队列。
    • 未完成连接队列:每个处于三次握手中的TCP连接,套接字处于SYN_RCVD状态。
    • 已完成连接队列:每个已完成三次握手的TCP连接,套接字处于ESTABLISHED状态。

    这2个队列之和不能超过__n,否则就无法新建TCP连接,这就是SYN Flood攻击的原理。

    5 accept函数

    // sys/socket.h extern int accept (int __fd, __SOCKADDR_ARG __addr,socklen_t *__restrict __addr_len);

    accept函数由TCP服务器调用,用于从已完成连接队列的队头返回下一个已完成连接。如果该队列为空,那么进程被投入睡眠。(默认套接字为阻塞方式)

    参数__addr和__addr_len返回已连接的对端进程的协议地址,即返回客户端的协议地址。__addr_len是值-结果参数,返回内核存放在协议地址中实际的字节数。如果对客户端的协议地址不感兴趣,可以将指针置为NULL。

    注意:如果accept成功,返回值是又内核自动生成的全新描述符,称为已连接套接字。服务端与客户通信,将用这个套接字,服务完成后,这个套接字就被关闭。 而参数__fd称为监听套接字, 一个服务仅仅创建一个监听套接字。

    6 close函数

    // /usr/include/unistd.h extern int close (int __fd);

    close函数一般可以用来关闭套接字,并终止TCP连接。但是在并发服务器中,close函数仅仅将套接字描述符引用计数减1。所以并不能一定在TCP连接上发送FIN报文,如果想在TCP连接上发送FIN报文,可以用shutdown函数。

    参考文献:《UNIX网络编程 卷1:套接字联网API》

    总结

    以上是生活随笔为你收集整理的accept函数_基础套接字函数入门1的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。