Socket编程(day14)

一、基于TCP传输层的编程模型
TCP是面向连接的,安全可靠的。
三次握手
服务器端编程模型
1、创建一个用于网络通讯的设备 通讯端点
socket(2)
#include  <sys/types.h>
#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:
0
返回值:
-1  错误 errno被设置
返回一个新的文件描述符

2、将这个通讯端点和本机的ip地址、端口号做绑定
bind(2)
int bind(int sockfd, const struct sockaddr *addr,
                socklen_t addrlen);
功能:绑定名字到地址。创建socket以后,socket中有地址空间但是没有具体地址放在这个地址空间。需要将具体的地址和socket的地址空间绑定。
参数:
sockfd:已经创建好的socket,但是这个socked没有具体的地址
addr:指定了具体的地址,将这个地址绑定到sockfd中
addrlen:指定了addr的大小、字节数
返回值:
0  成功
-1  错误  errno被设置

地址家族的通用结构

struct sockaddr{
    sa_family_t sa_family;
        char        sa_data[14];
};

ipv4和ipv6
man in.h
#include <netinet/in.h>
in_port_t    uint16_t
in_addr_t    uint32_t
sa_family_t  <sys/socket.h>

struct in_addr{
    in_addr_t  s_addr;
};

ipv4的具体地址
struct sockaddr_in{
    sa_family_t     sin_family;   //AF_INET.
        in_port_t       sin_port;     //Port number.
        struct in_addr  sin_addr;     //IP address.
};

INADDR_ANY   IPv4 local host address
这是一个宏,宏的本质是一个整数。代表了本机的所有的地址。



端口号   0~65535
但是5000以下最好不要用。因为已经被国际组织使用了。

sin_port  采用网络字节序
需要将本机字节序的数字转换为网络字节序
系统提供了函数。处理本机字节序和网络字节序的问题
#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    to


ip地址  字符串格式    二进制格式  互相转换
inet_pton(3)
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
功能:从字符串格式转换为二进制格式   IPV4 IPV6
参数:
af:
AF_INET or AF_INET6

src:字符串格式的ip地址
dst:存储了网络地址结构的信息
返回值:
1   成功
0  src无效
-1  错误  errno被设置

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

ip地址  127.0.0.1  本地地址   环回地址
测试机器的网络设备工作是否正常。

setsockopt(2)

3、在这个通讯端点上监听客户端连接的到来,如果有连接的到来,将到达的连接存放在缓冲区中(队列的数据结构)
listen(2)
int listen(int sockfd, int backlog);
功能:在socket监听连接。将sockfd标记为被动连接。接收即将到来的客户端请求。
参数:
sockfd:指定了被监听的socket
backlog:指定了未决连接的最大数。
返回值:
0  成功
-1   错误   errno被设置

4、从这个缓冲区队列中取出一个客户端连接,返回一个连接描述符用于和客户端的通讯。(这个连接描述符称为conn_fd)
accept(2)
int accept(int sockfd, struct sockaddr *addr, \
        socklen_t *addrlen);
功能:在socket上接收一个连接
参数:
sockfd:指定了监听的socket
addr:在这个地址空间里填充了客户端的地址和端口号
addrlen:空间里指定了addr的长度。如果addr为NULL,那么也要设置为NULL
返回值:
-1  错误   errno被设置
返回一个非负的整数,就是连接描述符

5、使用conn_fd和客户端通讯
(1)获取客户端的请求
read(2)
(2)处理客户端请求
(3)响应客户端
write(2)

6、关闭conn_fd,终止和客户端的通讯
close(conn_fd);

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

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

举例说明  编写基于TCP的通讯模型
服务器端代码  参见   server.c
客户端代码参见   client.c
172.30.3.93

二、并发服务器的实现
三种方法实现服务器的并发    多进程   多线程    多路复用
使用多进程实现服务器的并发功能
什么时候?什么地方?子进程才登场。
fork(2)

子进程负责的任务
子进程负责和客户端的通讯
关闭s_fd。
信息处理
关闭和客户端的连接


父进程负责的任务
父进程负责从未决连接队列中取出一个连接,创建和客户端通讯的文件描述符
创建子进程

关闭和客户端的连接
负责对子进程收尸。非阻塞收尸

 

posted @ 2017-10-25 21:57  Kernel001  阅读(226)  评论(0编辑  收藏  举报