linux socket 学习(介绍1)

            Sockets是IPC的一个方法,允许数据在应用之间交换, 无论是在同一台主机还是在连接到网络的不同的主机。 第一个普遍Sockets API的实现出现在1983年4.2BSD系统,这个API已经运用到没一个UNIX实现中,如同大部分操作系统一样。

                            (Socket API在POSIX标准中正式规格化)。

            下面我们就介绍sockets的使用,包括:

            (1) 介绍sockets API,它的基本原理,我不贴出具体的实现代码。

            (2) 描述UNIX域scokets, 它允许在同一个主机系统中应用互相通信。

            (3) 介绍不同的计算机网络概念并描述TCP/IP网络协议的关键的特性。

            (4) 介绍网络域sockets, 它允许在不同的主机上的应用通过TCP/IP网络通信。

            (5) 介绍使用scokets的服务器设计。

            (6) 介绍一些高级特性,包括socket I/O的格外特性, 更详细的TCP协议, socket选项的使用来检索和修改sockets的不同属性。

             1. 回顾:

                 在典型的客户-服务器场景, 应用一般是这样使用sockets的:

                      * 每一个应用创建一个socket. 它是应“容器” 允许互相通信。

                      * 服务器通过确认的地址(名字)来绑定这个socket, 那么客户可以定位到它。

                socket 使用socket()系统调用来创建, 它返回一个文件描述符来指向接下来的socket的系统调用:

                      fd = socket(domain, type, protocol); protocol 总是0;

            2. 通信域

                 Sockets存在于通信域,有以下决定:

                        * 认证socket的方法(比如,socket地址的格式)

                        * 通信范围(比如, 在同一个主机上不同应用,或者通过网络连接的不同主机的不同应用)。

           3. 现代的操作系统至少支持以下的域:

                        * Unix(AF_UNIX)域,它允许在同一台主机上的应用之间通信。(在POSIX中,AF_LOCAL和AF_UNIX,但是它不用于SUSv3)

                        * IPv4(AF_INET)域, 它允许在网络中的不同主机的应用通过IPv4来通信。

                        * IPv6 (AF_INET6) 域。

                        在一些代买中,我们看到使用PF_UNIX,而不用AF_UNIX。 在这里,AF 代表“地址家族” 而PF代表的是“协议家族”。起初,我们认为单一的协议家族可以支持多个地址家族,但在实践中,支持多地址家族的单一协议家族还没有定义。


             4. Socket 类型

                  每一个sockets实现都提供两种sockets类型:流和数据报。消息类型在UNIX和网络域中都支持。

                  总结: 流式是可靠的传送,而数据包方式不是, 流式不是保存的消息边缘,而数据包可以,流式是面向连接的,而数据报不是的。

                   Stream sockets (SOCK_STREAM)提供可靠,双向,字节流通信通道。在网络域中,数据报socket部署UDP,而流sockets部署TCP。 代替词条Internet domain datagram 和 Internet domain stream socket, 我们经常使用UDP和TCP socket.


             5. Socket 系统调用

                  * socket()系统调用创建一个新的socket

                  * bind() 系统调用把socket 绑定到一个地址。 通常,服务器部署这个调用来绑定到一个认知的地址,可以让客户定位到这个socket.

                  * listen() 系统调用允许流socket接收从其它sockets来的连接。

                  * accept() 系统调用接收一个监听流socket的对等应用的连接, 可选的返回对等socket的地址。

                  * connect() 系统调用和令一个socket建立连接。

                    Socket I/O可以使用常规函数read() 和write() 系统调用,或者使用socket指定的系统调用(如send(), recv(), sendto(), 和recvfrom()). 默认,如果I/O操作不是立即完成,系统调用就会被阻塞,没有不阻塞的I/O,通过使用fcntl() F_SETFL操作来启动O_NONBLOCK 的打开文件标志。

                    (在linux 中, 我们调用ioctl(fd, FIONREAD, cnt) 来获取没流socket中没有读的可用字节,当然我们要针对fd这个文件描述符, 对于数据报socket,在下一个没有读取到的数据报会返回字节的数量(如果下一个数据报是0长度,可能返回0))

                 说明,socket中最后一个参数一般为0, 无零的协议值用于其它的socket类型,比如,我们使用IPPROTO_RAW对应raw sockets (SOCK_RAW)

             6. bind() ; #include <sys/socket.h> int bind(int scokfd, const struct sockaddr * addr, socklen_t addrlen)

             我们有时候不需要调用bind(), 而直接调用listen(), 这样的话,内核就会选择一个一次性的端口来通信。之后,服务器需要用getsockname()函数来检索他的socket地址。这样的话,服务器必须要提供一个客户端知道连接到什么地方的地址。 我们可以注册服务器地址到中心目录服务器(centralized directory service application)来提供服务器地址。(比如,Sun RPC 使用端口映射服务来解决这个问题)。 当然此中心目录服务应用必须有服务器的地址。

             struct sockaddr: 每一个socket域都要求不同的地址类型,比如UNIX要的路径,而INTERNET需要的地址和端口,都不是统一的,所以我们要使用一个基本的结构来接收这些所有的类型,那就是socketaddr.

            7. 流socket

                流的socket系统调用好比如电话系统: (1) socket()相当于安装一台电话,没一台电话都要创建一个socket. (2)一个电话必须要连接到另一个电话上的socket上,连接过程如:(a)一个调用bind()绑定地址,然后listen()来接收连接(如我们有一个电话号码,确保电话打开,等待有人连接)。(b)令一个应用通过connect()来建立连接,具体到哪个以地址的socket来连接,如果大电话给某个人。(c)监听的用户使用accept()来接收数据。如同电话铃响,接听电话。如果在连接之前对方就接收了其它的用户,那就会等待。(3)建立连接之后就会通话。 如read() , write(),和一些socket指定的send()和recv()。

            8. 主动和被动sockets

                * 默认的情况下,我们使用socket()建立的是主动的,主动的socket可以使用connect()来年接到被动socket. 这被认为是主动开启。

                * 被动socket(也称作监听socket) 被标志为仅仅调用listen()来监听连接,接收一个连接被称作被动开启。

            9. listen();  #include <sys/socket.h> int listen(int sockfd, int backlog); 监听只能在此连接不接收信息的时候使用,所以这里的backlog用来表示挂起连接数。比如服务器正在忙碌其它的事情,没有相应连接,就会造成阻塞。SUSv3通过在<sys/socket.h>中的SOMAXCONN常量来报道上线,在Linx中,是128,但是从2.4.25内核可以运行时进行修改,/proc/sys/net/core/somaxconn文件。

            10. accept() : #include <sys/socket.h> int accept(int, sockfd, struct sockadrr * addr, socklen_t *addrlen);最后一个参数必须初始化到指向addr的缓冲区大小,那么内核可以知道多大的空间是可用的。如果不看到对方的信息,可以填入null, 0. 然后同个getpeername()系统调用来获取。

            11. connect(); #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr, sockelen_t addrlen); 当我们试图重新连接的时候就会报错。

            12. close(): 我们通常使用它来关闭一个流socket. 如果多个文件描述符指向同一个socket, 那么只有当所有的描述符关闭连接才断开。有些时候当我们关闭连接之后,对方的应用崩溃或者不能读取数据,如果是这样,我们就无法知道错误的发生,我们需要有一个好的协议机制来保护这中情况, 我们采用shutdown()系统调用,它可以很好的控制流socket连接的关闭。


            二。数据报sockets

             数据报操作如同邮局系统:

              (1)socket()系统调用如同安装了邮箱。 每一个应用都想通过socket()来发送和接收数据报。

              (2)使用bind(),同上。

              (3)发送数据报,sendto(). 写入需要发送的地址。

              (4)接收数据报, recvfrom().

              (5) 关闭连接close();

              1. 实际函数

                        #include <sys/socket.h> ssize_t recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *src_addr, socklen *addrlen);

                        ssize_t sendto(int sockfd, const void *buffer, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);


               


            

    

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值