一、基于socket的一对一通信模型
1.1 相关函数的解析
(1)socket()
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能:
主要用于创建用于交流 / 通信的端点;
参数:
第一个参数:协议族/域,决定了本地通信还是网络通信;
AF_UNIX / AF_LOCAL - - - - - 表示实现本地通信
AF_INET - - - - - - - - - - - - - - - -表示实现基于IPv4的网络通信
第二个参数:具体的通信类型,决定了具体的通信协议;
SOCK_STREAM - - - - 提供有序的、可靠的、双向的、面向连接的字节流通信方式,也就是基于TCP协议的通信方式
SOCK_DGRAM - - - - - 提供不可靠的,非面向连接的数据报通信方式,也就是基于UDP协议的通信方式
第三个参数:具体的特殊协议,默认给0即可;
返回值:
success —- 文件描述符,error —- -1;
(2)通信地址的常用地址数据类型
a. struct sockaddr类型 - - - - 主要用于函数的形参类型,基本不会定义结构体变量去使用;
struct sockaddr
{
sa_family_t sa_family;
char sa_data[14];
}
b. struct sockaddr_un类型 - - - - 主要用于实现本地通信;
#include <sys/un.h>
struct sockaddr_un
{
sa_family_t sun_family; //协议族,和socket()的第一个实参保持一致即可;
char sun_path[]; //socket文件的路径名;
}
c. struct sockaddr_in类型 - - - - 主要用于网络通信;
#include <netinet/in.h>
struct sockaddr_in
{
sa_family_t sin_family; //协议族 AF_INET
in_port_t sin_port; //端口号
struct in_addr sin_addr; //IP地址
}
struct in_addr
{
in_addr_t s_addr; //整数类型的IP地址
}
(3)bind()
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:
主要用于绑定socket和指定的通信地址;
参数:
第一个参数:socket的描述符,socket()的返回值;
第二个参数:结构体指针,用于指定通信地址,需要进行类型转换;
第三个参数:通信地址的大小,使用sizeof()计算即可;
(4)connect()
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:
主要用于建立socket到通信地址的连接,参数和返回值参考bind()即可;
(5)字节序转换函数
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
/* 主要用于将32位二进制组成的主机字节序转换为网络字节序 */
uint16_t htons(uint16_t hostshort);
/* 主要用于将16位二进制组成的主机字节序转换为网络字节序 */
uint32_t ntohl(uint32_t netlong);
/* 主要用于将32位二进制组成的网络字节序转换为主机字节序 */
uint16_t ntohs(uint16_t netshort);
/* 主要用于将16位二进制组成的网络字节序转换为主机字节序 */
(6)IP地址的转换函数
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
功能:
主要用于将字符串形式的IP地址转换为整数类型的IP地址;
char *inet_ntoa(struct in_addr in);
功能:
主要用于将结构体类型的IP地址转换为字符串类型;
二、基于TCP协议的网络通信模型
2.1 通信模型
服务器:
(1)创建socket,使用socket();
(2)准备通信地址,使用结构体类型;
(3)绑定socket和通信地址,使用bind();
(4)监听,使用listen();
(5)响应客户端的连接请求,使用accept();
(6)进行通信,使用send()/recv();
(7)关闭socket,使用close();
客户端:
(1)创建socket,使用socket();
(2)准备通信地址,使用服务器的地址;
(3)连接socket和通信地址,使用connect();
(4)进行通信,使用send()/recv();
(5)关闭socket,使用close();
2.2 相关函数的解析
(1)listen()
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
功能:
主要用于将参数sockfd所指定的socket标记为被动的socket,也就是原来的socket是可以用于通信的,但是标记为被动的socket之后,专门用于响应即将到来的连接请求,不再用于通信;
参数:
第一个参数:socket描述符,socket()的返回值;
第二个参数:主要用于指定悬而未决连接请求队列的最大长度,当该队列为满时,有客户端发来连接请求,则会被拒绝;
(2)accept()
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:
主要用于响应指定socket上面的一个连接请求;该函数会提取悬而未决连接请求队列中的第一个连接请求进行响应,响应的方式就是再创建一个连接好的socket进行通信;
参数:
第一个参数:socket的描述符,socket()的返回值;
第二个参数:结构体指针,用于带出客户端的通信地址;
第三个参数:指针类型,用于带出客户端通信地址的大小;
返回值:
success —- 通信socket的描述符,error —- -1;
(3)send()
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:
主要用于向指定的socket发送指定的数据内容;
参数:
第一个参数:socket描述符,用于通信的socket;
第二个参数:被发送数据的首地址;
第三个参数:被发送数据的大小;
第四个参数:发送的标志,默认给0即可;
返回值:
success —- 实际发送数据大小,error —- -1;
(4)recv()
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:
主要用于接收参数指定socket中的数据;
参数:
第一个参数:socket描述符,用于通信的socket;
第二个参数:存放接收到数据的缓冲区首地址;
第三个参数:期望接收的数据大小;
第四个参数:接收的标志,默认给0即可;
返回值:
success —- 实际接收数据大小,error —- -1;
练习:
使用基于tcp协议的通信模型实现一对多通信
a. 要求服务器可以不断地响应客户端的连接请求;
=> 使用while(1)无限循环
b. 要求服务器可以同时接收多个客户端发来的消息;
=> 使用fork()创建子进程
c. 要求服务器可以和每一个客户端不断进行通信;
=> 使用while(1)无限循环
d. 要求当客户端发来”bye”时,表示客户端下线;
=> 使用strcmp()比较
e. 要求客户端发送的消息由键盘输入;
=> 使用scanf()/gets()/fgets()
f. 要求关闭服务器请按ctrl+c来实现;
=> 对信号SIGINT进行自定义处理
明日预报:
(1)网络编程;
(2)多线程;