美文网首页
学习Socket编程总结

学习Socket编程总结

作者: 晔兮如华 | 来源:发表于2018-04-18 12:26 被阅读86次

    什么是Socket

    Socket(套接字)是介于应用层和传输层之间(图1)的应用程序编程接口。多数应用程序是由通信进程对组成,每对中的两个进程互相发送报文,从一个进程向另一个进程发送的报文必须通过下面的网络。进程通过Socket(套接字)软件接口向网络发送报文和从网络接收报文。做个简单的类比,进程可类比于一座房子,而它的套接字可以类比于它的门。当一个进程向位于另外一台主机上的另一个进程发送报文时,它把报文推送出该门(套接字)。该发送进程假定该门到另外一侧之间有运输的基础设施,该设施将把报文传送到目的进程的门口。一旦该报文抵达目的主机,它通过进程的门(套接字)传递,然后接收进程对该报文进行处理。

    图1

    几种典型的Socket

    1.Berkeley UNIX 操作系统定义了一种 API,称为套接字接口(socket interface),简称套接字(socket)。

    2.微软公司在其操作系统中采用了套接字接口 API,形成了一个稍有不同的 API,并称之为Windows Socket Interface,WINSOCK。

    3.AT&T 为其 UNIX 系统 V 定义了一种 API,简写为 TLI (Transport Layer Interface)。

    (本文以WINSOCK为例)

    客户端Socket API函数

    TCP客户端软件流程

    1. 确定服务器IP地址与端口号

    2. 创建套接字

    3. 分配本地端点地址(IP地址+端口号)(此步骤由操作系统完成)

    4. 连接服务器(套接字)

    5. 遵循应用层协议进行通信

    6. 关闭/释放连接

    UDP客户端软件流程

    1. 确定服务器IP地址与端口号

    2. 创建套接字

    3. 分配本地端点地址(IP地址+端口号)(此步骤由操作系统完成)

    4. 指定服务器端点地址,构造UDP数据报

    5. 遵循应用层协议进行通信

    6. 关闭/释放套接字

    使用Socket的应用程序在使用Socket之前必须首先调用WSAStartup函数初始化Windows Sockets API

    int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

    其中第一个参数指明程序请求使用的WinSock版本,其中高位字节指明副版本、低位字节指明主版本,第二个参数返回实际的WinSock的版本信息

    int WSACleanup (void);

    应用程序在完成对请求的Socket库的使用,最后要调用WSACleanup函数解除与Socket库的绑定,释放Socket库所占用的系统资源

    创建socket

    socket sd = socket(protofamily,type,proto);

    操作系统返回套接字描述符(sd),其中第一个参数(协议族): protofamily = PF_INET(TCP/IP),第二个参数(套接字类型):type = SOCK_STREAM,SOCK_DGRAM or SOCK_RAW(TCP/IP),第三个参数(协议号):0为默认

    SOCKET sd=socket(PF_INET,SOCK_STREAM,0); (TCP)

    SOCKET sd=socket(PF_INET,SOCK_DGRAM,0); (UDP)

    图2

    TCP:可靠、面向连接、字节流传输、点对点

    UDP:不可靠、无连接、数据报传输

    int bind(sd,localaddr,addrlen);

    绑定套接字的本地端点地址,IP地址+端口号,客户程序一般不必调用bind函数

    connect(sd,saddr,saddrlen);

    客户程序调用connect函数来使客户套接字(sd)与特定计算机的特定端口(saddr)的套接字(服务)进行连接,connect函数仅用于客户端,可用于TCP客户端也可以用于UDP客户端。

    TCP客户端:建立TCP连接

     UDP客户端:指定服务器端点地址

    int closesocket(SOCKET sd);

    关闭一个描述符为sd的套接字,如果多个进程共享一个套接字,调用closesocket将套接字引用计数减1,减至0才关闭。如果一个进程中的多线程对一个套接字的使用无计数,当进程中的一个线程调用closesocket将一个套接字关闭,该进程中的其他线程也将不能访问该套接字

    服务端Socket API函数

    服务端在创建完socket后也需要绑定本地地址,一般使用地址通配符:INADDR_ANY

    int listen(sd,queuesize);

    置服务器端的流套接字处于监听状态,仅服务器端调用面向TCP的scocket,设置连接请求队列大小(queuesize)

    newsock = accept(sd,caddr,caddrlen);

    服务程序调用accept函数从处于监听状态的流套接字sd的客户连接请求队列中取出排在最前的一个客户请求,并且创建一个新的套接字来与客户套接字创建连接通道

    send(sd,*buf,len,flags);

    sendto(sd,*buf,len,flags,destaddr,addrlen);

    send函数用于TCP套接字(客户与服务器)或调用了connect函数的UDP客户端套接字。sendto函数用于UDP服务器端套接字与未调用connect函数的UDP客户端套接字

    recv(sd,*buffer,len,flags);

    recvfrom(sd,*buf,len,flags,senderaddr,saddrlen);

    recv函数从TCP连接的另一端接收数据,或者从调用了connect函数的UDP客户端套接字接收服务器发来的数据。recvfrom函数用于从UDP服务器端套接字与未调用connect函数的UDP客户端套接字接收对端数据。

    int setsockopt(int sd, int level, int optname, *optval, int optlen);

    int getsockopt(int sd, int level, int optname, *optval, socklen_t *optlen);

    setsockopt()函数用来设置套接字sd的选项参数。getsockopt()函数用于获取任意类型、任意状态套接口的选项当前值,并把结果存入optval。

    网络字节顺序

    1.TCP/IP定义了标准的用于协议头中的二进制整数表示:网络字节顺序(network byte order)

    2.某些Socket API函数的参数需要存储为网络字节顺序(如IP地址、端口号等)

    3.可以实现本地字节顺序与网络字节顺序间转换的函数

    htons: 本地字节顺序→网络字节顺序(16bits)

    ntohs: 网络字节顺序→本地字节顺序(16bits)

    htonl: 本地字节顺序→网络字节顺序(32bits)

    ntohl: 网络字节顺序→本地字节顺序(32bits)

    网络应用的Socket API(TCP)调用基本流程

    4种类型基本服务器

    1.循环无连接(Iterative connectionless)服务器

    2.循环面向连接(Iterative connection-oriented)服务器

    3.并发无连接(Concurrent connectionless)服务器

    4.并发面向连接(Concurrent connection-oriented)服务器

    循环无连接服务器基本流程

    1. 创建套接字

    2. 绑定端点地址(INADDR_ANY+端口号)

    3. 反复接收来自客户端的请求

    4. 遵循应用层协议,构造响应报文,发送给客户

    服务器端不能使用connect()函数,无连接服务器使用sendto()函数发送数据报

    调用recvfrom()函数接收数据时,自动提取客户端点地址

    循环面向连接服务器基本流程

    1.创建(主)套接字,并绑定熟知端口号;

    2.设置(主)套接字为被动监听模式,准备用于服务器;

    3.调用accept()函数接收下一个连接请求(通过主套接字),创建新套接字用于与该客户建立连接;

    4.遵循应用层协议,反复接收客户请求,构造并发送响应(通过新套接字);

    5.完成为特定客户服务后,关闭与该客户之间的连接,返回步骤3.

    并发无连接服务器基本流程

    主线程1: 创建套接字,并绑定熟知端口号;

    主线程2: 反复调用recvfrom()函数,接收下一个 客户请求,并创建新线程处理该客户响应;

    子线程1: 接收一个特定请求;

    子线程2: 依据应用层协议构造响应报文,并调用sendto()发送;

    子线程3: 退出(一个子线程处理一个请求后即终止)。

    并发面向连接服务器基本流程

    主线程1: 创建(主)套接字,并绑定熟知端口号;

    主线程2: 设置(主)套接字为被动监听模式,准备用于服务器;

    主线程3: 反复调用accept()函数接收下一个连接请求(通过主套接字),并创建一个新 的子线程处理该客户响应;

    子线程1: 接收一个客户的服务请求(通过新创建的套接字);

    子线程2: 遵循应用层协议与特定客户进行交互;子线程3: 关闭/释放连接并退出(线程终止).

    相关文章

      网友评论

          本文标题:学习Socket编程总结

          本文链接:https://www.haomeiwen.com/subject/jlfvkftx.html