您的位置:首页 > 理论基础 > 计算机网络

【C语言】【unix c】基于TCP传输层的编程模型

2017-09-28 23:09 183 查看
一、基于TCP传输层的编程模型
流程:
服务器上可以同时工作多个服务端,以一个服务端为例,一个服务端相当于一个设备,在LINUX下也就是一个文件,这个文件对应了一片存储区域,这个区域里记录各种信息。因此在建立服务端的时候需要先创建一个设备(文件)->创建好的设备里没有信息,我们需要添加一些信息来用于与外界的通信。我们知道要通信需要知道互相的ip,端口信息。所以我们将本机的ip地址和端口号与创建好的设备绑定,让该ip和端口的结合作为该设备的标示->自身准备好就需要与客户端建立链接,因此服务端就需要监听看看谁要链接服务端->发现请求对象后需要建立链接,建立链接的方式是创建一个用于通讯的文件,该通讯文件记录了客户链接本机的哪个服务端及谁连的。->链接成功后开始进行信息处理->处理完成后结束链接,但是服务端不会结束,继续监听。

服务器端的编程模型:
1、创建一个用于网络通信的设备(通讯端点)(创建一个文件描述符,这里的文件描述符是用于创建设备的)
socket(2)
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能:(套接口)创建一个用于通信的端点。
参数:
domain:选择协议家族
AF_INET:应用于IPV4地址家族
AF_INET6:应用于IPV6地址家族
type:
SOCK_STREAM:可靠的,基于链接的,双向的,队列式的 TCP
SOCK_DGRAM:数据包 支持不可靠的,无链接的 UDP
protocol:指定应用程序所使用的通信协议。在Internet中一般设置为0
0
返回值:返回一个新的文件描述符
-1 错误 errno设置

2、将这个通讯端点和本机的ip地址,端口号做绑定
bind(2)
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:(将一本地地址与一套接口捆绑)绑定名字到地址,创建socket以后,socket中有地址空间,但是没有具体地址放到这个地址空间,我们需要将具体的地址和socket的地址空间绑定
参数:
sockfd:已经创建好的socket,但是这个socket没有具体的地址
addr:指定了具体的地址,将这个地址绑定到socket中
addrlen:指定了addr的大小,是字节数
返回值:0 成功
-1 错误 errno被设置

3、在这个通讯端点监听客户端链接的到来,如果有链接到来,将到达的链接存放在缓冲区(队列的数据结构)
listen(2)
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
功能:(使套接字处于监听状态,该套接字将维护一个客户链接请求列对(未决链接队列))在scoket上监听链接,将socket标记为被动链接,接受即将到来的客户端请求,将链接追加到缓冲区,而accept将链接从队列取出
参数:
sockfd:指定了被监听的socket
backlog:指定了未决链接的最大数
返回值:0 成功
-1 错误 errno被设置

4、从这个缓冲区队列中取出一个客户端链接,返回一个链接描述符,用于和客户端的通信(这个链接描述符称为c_fd)(这里的文件描述符用于建立链接的,链接中断后是这里断开)
accept(2)
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:在socket上接收一个链接,从未决链接队列里取出第一个链接请求
参数:
sockfd:指定了监听的socket
addr:在这个地址空间里填充了客户端的地址和端口号,如果填为NULL则不会填充addrlen也设置为NULL
addrlen:空间里指定了addr的长度
返回值:返回一个非负的整数,就是链接描述符
-1 错误 errno被设置

5、使用c_fd和客户端通信
a、获取客户端的请求
read(2)
b、处理客户端的请求
write(2)
c、响应客户端
6、关闭c_fd,终止和客户端通信
close(2)

客户端的编程模型:
1、创建一个用于通信的设备(通信端点)
socket(2)
2、使用这个通信端点链接到服务器(需要知道服务器的IP和端口号)
connect(2)
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:在socket上发起一个链接
参数:
sockfd:指定socket,将这个socket链接到addr的地址空间
addr:指定了具体的地址空间,要链接到的地址空间(服务器端的)
addrlen:指定了addr的长度
返回值:0 成功
-1 错误 errno被设置

4000
3、向服务器发送消息
4、等待服务器端的响应
5、处理服务器的响应消息
6、关闭设备,结束通信

补充:
1、链接到达但是没有进行接通是未决链接

2、地址家族的通用结构:(通用结构是不能使用的,具体的使用结构和这个有点不一样)
struct sockaddr {
sa_family_t sa_family;  //地址家族,一般都是AF_XXX的形式,常用AF_INET,代表TCP/IP协议族
char        sa_data[14];//14字节的协议地址,指明地址信息,一般编程不会直接对此进行操作,而是用另一个与sockaddr等价的数据结构,像sockaddr_in
}
3、与sockaddr等价的数据结构可以使用【man in.h】察看,常用的有IPV4,IPV6的数据结构
#include <netinet/in.h>
in_port_t:uint16_t 无符号短整形
in_addr_t:uint32_t 无符号长整形/整形

IPV4具体的数据结构:
struct sockaddr_in{
sa_family_t     sin_family   //AF_INET.  指协议族,这里只能用AF_INET
in_port_t       sin_port     //Port number.  存储端口号(注意这里需要转换为网络字节序)
struct in_addr  sin_addr     //IP address.   存储ip地址(需要使用in_addr这个数据结构)
}
sockaddr_in和sockaddr是并列的结构,指向sockaddr_in的结构体的指针也可以指向sockaddr的结构体,并替代他。也就是说可以用sockaddr_in建立需要的信息,然后进行类型转换就可以了(struct sockaddr*)mycket

sa_family_t 在<sys/socket.h> 中定义

in_addr结构体:
struct in_addr{
in_addr_t s_addr;
}
本机ip地址初始化:
INADDR_ANY :IPV4 local host address 是一个宏,宏的本质是一个整数。这个宏代表了本机所有的地址
4、端口号是0~65535
但是5000一下最好不用,已经被国际组织使用

5、系统提供了函数来处理本机字节序和网络字节序的问题:
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);//主机字节序转换为网络字节序
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
h:host
n:net
s:short
l:long
t:to

6、ip地址的字符串格式和二进制格式间的互相转换
inet_pton(3)
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
功能:从字符串格式转换为二进制格式(ipv4和ipv6都支持)
参数:
af:
AF_INET:ipv4
AF_INET6:ipv6
src:字符串格式的ip地址
dst:存储了网络地址结构信息
返回值:1 成功
0 代表src无效
-1 错误 errno被设置

INET_NTOP(3)
#include <arpa/inet.h>
const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);
功能:将二进制到字符串的转换
参数:
af:
AF_INET:ipv4
AF_INET6:ipv6
src:在struct in_addr
dst:用于存储字符串的空间
size:指定了空间的有效字节数
返回值:非空,返回dst的地址,字符串的首地址
NULL 错误 errno被设置

127.0.0.1: 本地地址,环回地址,用于测试本机的网络设备工作是否正常

setsockopt()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unix c语言 编程 tcp