基本TCP套接字编程

    xiaoxiao2022-07-07  155

    目录

    TCP客户/服务程序的套接字函数框架

    socket函数

    connect函数

    bind函数

    listen函数

    accept函数

    fork和exec函数

    并发服务器

    close函数

    getsockname和getpeername函数


    TCP客户/服务程序的套接字函数框架

     

    socket函数

    作用:指定期望的通信协议类型

    family是以下表中的某个值,代表协议族 type指明套接字的类型 protocol会设置为以下表中的某个值,或者为0,以选择所给定的family和type组合的系统默认值 并非所有的family和type的组合都是有效的,常见的组合如下表

     

    connect函数

    作用:TCP客户使用connect函数来建立与TCP服务器的连接

    sockfd是由socket函数返回的套接字描述符 servaddr是一个指向套接字地址结构的指针 addrlen是套接字地址结构的大小

    客户在调用函数connect之前不必非得调用bind函数

    如果是TCP套接字,调用connect函数会触发TCP的三次握手过程,而且仅在连接建立成功或出错时才返回 其中出错可能有以下几种情况

    按照TCP的状态转移图,connect函数导致当前套接字从CLOSED状态转移到SYN_SENT状态,若成功则再转移到ESTABLISHED状态。 如果connect失败,那么该套接字不再可用,必须关闭,不能再对这样的套接字再次调用connect函数,必须close当前的套接字描述符并重新调用socket函数

    bind函数

    作用:把一个本地协议地址赋予一个套接字

    参数含义同connect函数 对于TCP,调用bind函数可以指定一个端口号,或指定一个IP地址,或者都指定,或都不指定

    服务器在启动时捆绑它们的总所周知的端口(为了对应的协议可以通过服务器的固定端口号发起连接) 如果一个TCP客户或服务器没有调用bind捆绑一个端口,那么继续往后调用connect和listen时,内核就要为相应的套接字玄子一个临时端口,这对服务器来说是很少不调用bind的,因为服务器的端口是被公认固定的

    进程可以把一个特定的IP地址捆绑到它的套接字上,但这个IP地址必须属于其所在的主机的网络接口之一,这样做的话,对TCP客户来说,就为该套接字上发送的IP数据报指派了源IP地址,对服务器来说,这就限定了该套接字只接收那些目的地为这个IP地址的客户连接。一般来说,TCP客户不把IP地址绑定到它的套接字上,而是让内核根据所用外出网络接口来选择源IP地址

    调用bind可以指定IP地址或端口,可以都指定,也可以都不指定,不同指定的结果如下 具体设置0和非0的做法参阅书本83页 如果让内核来为套接字选择一个临时端口,必须要注意的是,函数bind不返回所选择的值,为了得到内核所指定的这个临时端口值,需要调用函数getsockname来返回协议地址  

    listen函数

    作用: 1、把一个未连接的套接字转换成一个被动套接字(从CLOSED状态转换成LISTEN状态),指示内核应该接受指向该套接字的连接请求

    第二个参数backlog指定了内核应该为相应套接字排队的最大连接数 要理解backlog这个参数,就需要认识到内核为任何一个建庭套接字维护2个队列: 1、未完成连接队列,已由某个客户发出并到达服务器,而服务器正在等待完成相应的TCP三次握手过程,这些套接字处于SYN_RCVD状态,就会放在未完成连接队列 2、已完成连接队列,每个已完成TCP三次握手过程的客户都会放在已完成连接队列,这些套接字处于ESTABLISHED状态 图示   需要注意的是,不要把backlog定义为0,因为不同的实现对此有不同的解释,如果不想让任何用户连接到你的监听套接字上,就把套接字关掉  

    accept函数

    作用:accept函数由服务器调用,用于从已完成连接队列对头返回下一个已完成连接(如果已完成连接队列为空,那么进程被投入睡眠)

    参数cliaddr和addrlen用来返回已连接的对端进程的协议地址 如果accept成功,那么其返回值是由内核自动生成的一个全新描述符,代表与所返回客户的TCP连接  

    fork和exec函数

    fork返回2次,在父进程中返回一次,返回的是进程ID号,在子进程中返回一次,返回的是0, 因此,返回值本身告诉当前进程是子进程还是父进程 父进程调用accept函数后调用fork,所接受的已连接套接字随后就在父进程与子进程之间共享,通常情况下,子进程接着读写这个已连接套接字,父进程则关闭它

    fork有2个典型的用法: 1、一个进程创建一个自身的副本,这样每个副本都可以在另一个副本执行其它任务的同时处理各自的某个操作 2、一个进程想要执行另一个程序,就需要首先调用fork创建一个子进程,然后在子进程中调用exec把自身替换成新的程序

    存放在硬盘上的可执行文件能被Unix执行的唯一方法是:由一个现有进程调用6个exec函数中的某一个 6个exec函数如下: 这些函数只有在出错的时候才会返回到调用者,否则,控制将被传递给新程序的main函数 6个exec函数的关系如下图所示:  

    并发服务器

    Unix中编写并发服务器最简单的方法就是fork一个子进程来服务每个客户,如下图给出了一个典型的并发服务器程序的轮廓

    当一个连接建立时,accept返回,服务器接着调用fork,然后子进程服务客户,新的客户由子进程提供服务,父进程就关闭已连接套接字,然后等待下一个连接 图示:  

    close函数

    作用:关闭套接字,终止TCP连接

    描述符引用计数: 并发服务器中父进程关闭已连接套接字只是导致相应的描述符引用计数减1,如果引用计数值仍然大于0,那么这个close并不会引发四次握手终止连接 如果我们想在某个连接上忽视引用计数直接关闭连接,那么可以通过调用shutdown函数以代替close函数  

    getsockname和getpeername函数

    getsockname返回某个套接字关联的本地协议地址 getpeername返回某个套接字关联的外地址协议

    end

    最新回复(0)