socket套接字 学习笔记一

教材:《linux程序设计第三版》

1.流程简述

 服务端:

 (1).首先,服务器应用程序用系统调用socket来声明二个套接字描述符;并用其中一个来为服务器创建一个未命名的套接字,它是系统分配给该服务器的一个类似文件描述符的资源,且不能被其他进程共享。

 (2).接下给套接字命名,指定套接字地址。

 (3).创建套接字队列,用于保存未处理的请求。

 (4).接收客户端的连接,进行业务处理。

 (5).关闭套接字。

 客户端:

 (1).声明一个套接字描述符。

 (2).为客户创建一个套接字并命名,指定套接字地址。

 (3).将该套接字连接到服务器的套接字。

 (4).通过这个套接字来进行I/O操作。

 (5).关闭套接字。

 


2.套接字属性

 套接字的域:

 域指定套接字通信中使用的网络介质。常见的有AF_INET-UNIX网络套接字(ARPA因特网协议),linux局域网、因特网使用的是它;AF_UNIX-文件系统套接字(UNIX域协议),基于UNIX、LINUX文件系统实现的本地套接字。

 除了上二种最常用的,还有AF_ISO、AF_XNS等套接字使用的域。

 套接字类型:

 一个套接字的域可能有多种不同的通信方式,每种通信方式有不同的特性。

 因特网协议提供了两种不同的服务:流(stream)和数据报(datagram)

 流套接字有某些方面类似于标准的输入输出流,它提供一个有序,可靠,双向字节流的连接。因此可以保证发送的数据不会丢失、复制或乱序到达,大的消息会被分片、传输再重组。流套接字由类型SOCK_STREAM指定,在AF_INET域中通过tcp/ip连接实现,AF_UNIX域也常用该类型。

 数据报流(SOCK_DGRAM)指定的套接字不建立和维持一个连接;它对发送的数据长度也有限制,数据报被传输时有可能丢失、复制或乱序到达。数据报套接字在AF_INET域中通过udp/ip连接实现,它提供一种不可靠服务,但好处是资源开销较小,因为不用维持连接,且因此速度也很快。

 套接字协议:

 如果底层的传输机制允许,就可以为套接字选择一个特定的协议。不过一般在UNIX网络套接字和文件系统套接字中不需要指定,使用默认的即可。


3.创建套接字

 socket系统调用可以创建一个套接字并返回一个描述符,通过该描述符可以访问套接字。

 #include <sys/types.h>

    #include <sys/socket.h>

    int sockfd;

    sockfd = socket(int domain, int type, int protocol );

 创建的套接字是一条通信线路的其中一个端点,domain指定套接字的域,type指定套接字类型,protocol指定套接字协议。

 可以使用read,write系统调来访问sockfd,用close来关闭。

 

4.套接字名字和地址

 每个套接字域都有自己的地址格式:

 AF_INET:

  #include <netinet/in.h>

  struct socket_in{

        short int                      sin_family;          /*套接字名,只能是AF_INET*/

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

        struct in_addr            sin_addr;            /*在服务端,是允许接入的客户端ip地址,在客户端,是服务器的ip地址。 in_addr结构体只有一个成员,即unsigned long int类型的s_addr*/

        };

 AF_UNIX:

        #include <sys/un.h>

        struct socket_un{

        sa_family_t                sun_family;        /*套接字名,只能是AF_UNIX,sa_family_t 其实就是短整型*/

        char                             sun_path[];        /*地址,从多个例子上看到的是"server_socket",不知道什么意思*/

        };


5.套接字命名

 通过套接字命名,使AF_INET套接字关联一个ip端口号,AF_UNIX关联到一个文件系统的路径名,套接字才能被使用。客户端没有这一步。

  #include <sys/socket.h>

  int bind(int socket, const struct sockaddr *address, size_t address_len);

 bind把参数address中的地址分配给文件描述符相关联的未命名套接字。 address_len传递地址结构体的长度。

 成功返回0;失败返回-1,并设errno为以下相应值:

 EBADF            文件描述符无效

 ENOTSOCK                        文件描述符对应的不是一个套接字

 EINVAL                          文件描述符对应的套接字已命名

 EADDRNOTAVAIL                      地址不可用

 EADDRINUSER                      该地址已经绑定了一个套接字

 EACCESS            因权限不足,不能创建文件系统中的路径名

 ENOTDIR,ENAMETOOLONG  文件名不符合要求


6.创建套接字队列

 服务器程序为socket创建一个队列,用来保存未被处理的连接请求。客户端没有这一步。

 #include <sys/socket.h>

 int listen(int socket, int backlog);

 backlog是队列长度,在套按字队列中,等待处理的连接请求个数不能超过这个数,超过的请求将被拒绝。backlog常被设为5。

 成功返回0;失败返回-1,并设errno为以下相应值:EBADF、EINVA、ENOTSOCK,含义与前面的相同


7.接受连接

 一旦服务器程序创建并命名了一个套接字,它就可以通过accept系统调用来等待客户建立连接

 #include <sys/socket.h>

 int accept(int socket, struct sockaddr *address, size_t address_len);

 accept系统调用只有在有客户程序试图连接到由socket参数关联的套接字上时返回。它会为客户创建一个新的套接字与该客户通信,并返回新套接字的描述符,新套接字的类型与前面创建的套接字(又名服务器监听套接字)类型是一样的。

 如果队列中没有未处理的连接请求,accept会阻塞直到有客户请求建立连接为止。这一行为可以被改变,例如用

 int flag = fcntl(socket, F_GETFL, O_NONBLOCK);

 fcntl函数将套接字描述符的flags设为O_NONBLOCK,因此队列中没有未处理的连接时,accept不会阻塞,而是返回-1,并设errno为EWOULDBLOCK,如果accept被信号中断,errno则设为EINTR。可以使用fcntl函数将套接字描述符的标志设回0。


8.请求连接

 客户端程序通过一个未命名的套接字和服务器监听套接字之间建立连接的方法来连接服务器,通过connect函数来完成这一工作。服务端没有这一步。

 #include <sys/socket.h>

 int connect(int socket, const struct sockaddr *address, size_t address_len);

 socket是客户端定义的未命名的套接字,address是客户端定义的地址结构,它指明要连接到的服务器套接字。

 成功时返回0;失败返回-1,可能的错误码:

 EBADF                                    文件描述符无效

 EALREADY       该套接字上已有一个正在进行的中的连接

 ETIMEDOUT        连接超时

 ECONNREFUSED    连接请求被服务器拒绝

    与accept类似,如果连接不能被建立,connect将阻塞一段不确定的时间,一旦这个超过这个时间,连接将会被放弃,connect调用失败。connect调用的阻塞特性可通过设置该文件描述符的O_NONBLOCK来改变。

 如果connect调用被一个信号中断,且该信号又得到了处理,connect调用返回-1,将errno设为EINTR,但连接不会被放弃,而是转为异步连接方式。异步连接难于处理,我们可以用select调用来表明套接字已处于写就绪状态。


9.关闭套接字

 使用close()调用关闭套接字。

 要在服务的两端都关闭。对于服务器来说,应在read调用返回0时关闭,但如果套接字是一个面向连接类型的,且设置了SOCK_LINGER选项,close调用会在该套接字上还有未传输数据时阻塞。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值