UNIX编程--TCP套接字编程API

 

1.TCP 套接字编程API

1.TCP套接口编程--服务器函数

1.1.TCP函数调用流程图

套接字工作过程如下:

服务器首先启动,通过调用socket()建立一个套接字,然后调用bind()将该套接字和本地网络地址联系在一起,再调用listen()使套接字做好侦听准备,并规定它的请求队列的长度,之后调用accept()来接收链接。客户在建立套接字之后就可调用connect()和服务器连接。连接一旦建立,客户机和服务器之间就可以通过调用read()和write()来发送和接收数据。最后待数据传输结束后,双方调用close()关闭套接字。

1.2.socket函数

int socket(int family,int type,int protocol);

描述:进行TCP/IP通信之前必须建一个套结字,它规定了我们使用什么协议,使用什    

      么数据包,有了这些规定以后我们才好传数据。它的返回值我们叫做套结字描述

      符(socket descriptor),简写(sockfd)。

参数:family:  AF_INET-----IPv4协议

                    AF_INET6----IPv6协议

 AF_LOCAL---Unix域协议

 AF_ROUTE---路由器接口

 AF_KEY-------密钥接口

           Type  SOCK_STREAM--------字节流套接口

        SOCK_DGRAM---------数据包套接口

                 SOCK_SEQPACKET----有序分组套接口

             SOCK_RAW--------------原始套接口

   Protocol: IPPROTO_TCP------------TCP传输协议

             IPPROTO_UDP-----------UDP传输协议

     IPPROTO_SCTP----------SCTP传输协议

返回:成功返回一个非负的整数,出错返回-1;

1.3.bind 函数

int bind(int sockfd,const struct sockadd *myaddree,socklen_t addrlen)

描述:调用bind可以指定IP地址或端口,可以两者都指定,也可以不指定,一般我们 

      指定的IP地址就是本机的IP地址,端口就是提供某种服务的端口。

  其实就是将 套结字和IP地址和端口绑起来;这样的话在某一端我们就知道了使  

  用什么协议,自己这里的IP地址和端口。

参数:sockfd:套结字描述符;

          Sockadd 里面含有本定地址和端口,也可以将地址设置为通配地址,          

                  INADDR_ANY来指定通配地址,一般为0。它告知内核去选IP地址。

          Addrlen:就是指前面那个结构体的长度。

          struct sockaddr_in (in” 代表 “Internet)

          struct sockaddr_in {

short int sin_family; /* Internet地址族 */

unsigned short int sin_port; /* 端口号 */

struct in_addr sin_addr; /* Internet地址 */

unsigned char sin_zero[8]; /* 0(和struct sockaddr一样大 小)*/

};

返回:bind返回的常见错误是EADDRINUSSE;

1.4.Listen 函数

     int listen(int sockfd,int backlog)

     描述:listen()函数是等待别人连接,进行系统侦听请求的函数。当有人连接你的时候,   

           你有两步需要做:通过listen()函数等待连接请求,然后使用accept()函数来处理。    

          accept()函数在下面介绍)。那么我们需要指定本地端口了,因为我们是等待别 

           人的连接。所以,在listen()函数调用之前,我们需要使用bind() 函数来指定使       

           用本地的哪一个端口数值。

     参数: sockfd 是一个套接字描述符,由socket()系统调用获得。

            backlog 是未经过处理的连接请求队列可以容纳的最大数目。

            backlog 具体一些是什么意思呢?每一个连入请求都要进入一个连入请求队           

            列,等待listen 的程序调用accept()accept()函数下面有介绍)函数来接受这  

            个连接。当系统还没有调用accept()函数的时候,如果有很多连接,那么本地

            能够等待的最大数目就是backlog 的数值。你可以将其设成10 之间的数 

            值(推荐)。

     返回:listen()如果返回 –1 ,那么说明在listen()的执行过程中发生了错误。全局变量 

           errno 中存储了错误代码。

1.5.TCP的三次握手

     

当客户端SYN到达时,TCP再未完成连接的队列中创建一个新项,然后服务器SYN响应,其中捎带对客户SYN的ACK,这一项一直保存再未完成连接队列中,直到客户端对服务器

SYN的ACK到达或者超时为止。如果三次握手正常完成,该项就从未完成连接队列移到以完成队列的队尾。

当进程调用accept()的时候,以完成连接队列中的对头项将返回给进程。

1.6.accept 函数

int accept(int sockfd, void *addr, int *addrlen);

描述:accept()

有人从很远很远的地方尝试调用connect()来连接你的机器上的某个端口(当然是

你已经在listen()的)。

他的连接将被listen 加入等待队列等待accept()函数的调用(加入等待队列的最多

数目由调用listen()函数的第二个参数backlog 来决定)。

你调用accept()函数,告诉他你准备连接。

accept()函数将回返回一个新的套接字描述符,这个描述符就代表了这个连接!

好,这时候你有了两个套接字描述符,返回给你的那个就是和远程计算机的连接,而

第一个套接字描述符仍然在你的机器上原来的那个端口上listen()

1)服务器创建一个监听接口,它再服务器生命周期中一直存在。

2)内核为每个服务器进程接收的连接创建一个以连接套接口(也就是说三次握手已经完成)。  

  当服务器完成对于某个给定客户的服务时,相应的连接套接口就关闭。

这时候你所得到的那个新的套接字描述符就可以进行send()操作和recv()操作了。

参数:

     sockfd 是正在listen() 的一个套接字描述符。

     addr   一般是一个指向struct sockaddr_in 结构的指针;里面存储着远程连接过来的

              计算机的信息(比如远程计算机的IP 地址和端口)。

     Addrlen 是一个本地的整型数值,在它的地址传给accept() 前它的值应该是

               sizeof(struct sockaddr_in)accept()不会在addr 中存储多余addrlen bytes     

               小的数据。如果accept()函数在addr 中存储的数据量不足addrlen,则accept()         

               函数会改变addrlen 的值来反应这个情况。

返回:如果调用accept()失败的话,accept()函数会返回 –1 来表明调用失败,同时全局变量 

      errno 将会存储错误代码。

1.7.并发服务器

Unix编写并发服务器程序最简单的方法就是fock一个子进程来服务每个客户。

当一个连接建立时,accept返回,服务器接着调用fock,然后子进程服务客户(通过已连接套接口connfd),父进程则等待另一个连接。

我们可以想想,一个端口要给很多客户提供服务,所以它就建立那么多的子进程来提供服务,自己只管接收连接。

1.8.fork和exec函数

Fork调用一次,它却返回两次,它在调用进程(称为父进程)中返回一次,返回值是新派生进程(子进程)ID号,在子进程中又返回一次,返回值为0。

1.9. getpeername()函数

#include <sys/socket.h>

int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);

描述:

     这个函数可以取得一个已经连接上的套接字的远程信息(比如IP 地址和端口),告诉

     你在远程和你连接的究竟是谁.

参数:

   sockfd 是你想取得远程信息的那个套接字描述符。

addr 是一个指向struct sockaddr (或是struct sockaddr_in)的指针。

addrlen 是一个指向int 的指针,应该赋于sizeof(struct sockaddr)的大小。

返回:

如果在函数执行过程中出现了错误,函数将返回 –1 ,并且错误代码储存在全局变量

Errno 中。

当你拥有了远程连接用户的IP 地址,你就可以使用inet_ntoa() gethostbyaddr()来输

出信息或是做进一步的处理。

1.10. gethostname()函数

int gethostname(char *hostname, size_t size);

描述:

     gethostname()函数可以取得本地主机的信息.它比getpeername()要容易使用一些。

     它返回正在执行它的计算机的名字。返回的这个名字可以被gethostbyname()函数使用,

     由此可以得到本地主机的IP 地址。

参数:

     hostname 是一个指向字符数组的指针,当函数返回的时候,它里面的数据就是本

     地的主机的名字.

     size hostname 指向的数组的长度.

返回:函数如果成功执行,它返回0,如果出现错误,则返回–1,全局变量errno 中存储着 

      错误代码。

2.TCP套接口编程--客户端函数

2.1.connect函数

int connect (int sockfd, struct sockaddr *serv_addr, int addrlen);

描述:如果是TCP套接口,调用connect函数将激发TCP三次握手过程,而且紧连接成功 

      或出错返回。

      Connect函数导致当前的套接字接口从CLOSED状态(建立套接字一直处于的状态)     

      转移到SYS_SEND状态,若成功则再转移倒ESTABLISHED状态。

      注释:调用函数connect前不必非得调用bind函数,因为如果需要的话,内核会确定   

      源IP地址,并且选择临时端口。

参数:sockfd:是socket返回的套接字描述字。

      Serv_addr:是一个存储远程计算机的IP地址和端口信息结构。

      Addlen:应该是sizeof(struct sockaddr)

返回:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值