模拟智能家居项目
基本原理
-
socket套接字 socket是一个编程接口(网络编程接口) 是一种特殊的文件描述符(write/read) socket支持TCP协议 socket独立于具体的协议的编程接口,这个接口位于TCP四层模型的应用层与传输层之间。
-
基于TCP套接字编程流程
任何网络通信都有 通信双方: Client Server "网络地址" 任何网络应用一方都需要有一个“网络地址”(ip + 端口号) TCP网络应用的数据传输的大概过程: “三次握手” 发送/接收网络数据 write read 关闭连接: “四路挥手” TCP网络应用的编程流程 TCP Server 1.socket:创建一个套接字 2.bind:把一个套接字和网络地址 绑定在一起。 如果你想要让其他人来主动联系或连接你 你就需要bind一个地址,并且把这个地址 告诉其他人 3.listen:让套接字进入一个“监听模式” 4.accept:接收客户端的连接 多次调用accetp就可以与不同的客户 建立连接 5.write read 6.close:"四路挥手" TCP Client 1.socket: //2.bind:可要可不要 3.connect: 主动与TCP Server建立连接 “三次握手” 4.write read 5.close
-
socket具体的API函数解析
3.1头文件 #include <sys/types.h> #include <sys/socket.h> 3.2函数的功能 创建一个套接字文件 3.3函数的原型 int socket(int domain, int type, int protocol); 3.4函数的参数 int domain:指定域,协议族。socket 接口不仅仅局限于 TCP,它还可以用于bluetooth、... 每一种下面都有自己的许多的协议, AF_INET IPV4 协议族 AF_INET6 AF_BLUETOOTH int type: 指定要创建的套接字的类型 SOCK_STREAM : tcp int protocol:指定具体的应用层协议 可以指定为0(不知名的私有应用协议) 3.5函数的返回值: 成功:返回一个套接字描述符(> 0,文件描述符) 失败:返回-1
-
函数使用
4.bind函数 4.1头文件 #include <sys/types.h> #include <sys/socket.h> 4.2函数的功能 把一个网络地址IPV4 绑定到一个 socket上面去 4.3函数的原型 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 4.4函数的参数 int sockfd: 要绑定的地址的套接字描述符 const struct sockaddr *addr: 通用网络地址结构体的指针 socklen_t addrlen: 指定第二个实参指向的地址结构体的长度 4.5函数的返回值 成功:返回0 失败:返回-1 下午 1.网络地址结构体 通用的地址结构体: struct sockaddr //linux/socket.h { sa_family_t sa_family; //指定协议族 char sa_data[14]; } 以太网协议地址结构体: struct sockaddr_in { sa_family_t sin_family; //指定协议族 u_int16_t sin_port; //端口号 struct in_addr sin_addr; //ip地址 char sin_zero[8];//填充8个字节,为了和其他协议族地址结构体大小一样 } /*IP地址*/ struct in_addr { in_addr_t s_addr; } struct sockaddr_in a; //(struct sockaddr *)&a a.sin_family = AF_INET; a.sin_port = htons(10086); a.sin_addr.s_addr = inet_addr("192.168.0.102"); 2.ip地址之间的转换函数inet_addr() 2.1头文件 #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> 2.2函数的功能 把人认识的IP地址转换成计算机认识的IP地址 2.3函数的原型 in_addr_t inet_addr(const char *cp); 2.4函数的参数 const char *cp //填要转换的IP地址的字符串 2.5 函数的返回值 成功: 返回转换后的计算机识别的IP地址 失败: 返回-1; 3.主机字节序转换成网络字节序转换函数htons() 3.1头文件 #include <arpa/inet.h> 3.2函数的功能 将主机字节序转换成网络字节序 3.3函数的原型 uint16_t htons(uint16_t hostshort); 3.4函数的参数 uint16_t hostshort //填要转的字节序的数据 3.4返回值 成功:返回转换后的字节序数据 失败:-1 4.网络字节序转换成主机字节序转换函数ntohs() 5.让套接字进入”监听模式“API函数 listen() 5.1头文件 #include <sys/types.h> #include <sys/socket.h> 5.2函数的功能 让套接字进入监听模式 5.3函数的原型 int listen(int sockfd, int backlog); 5.4函数的参数 int sockfd //要进入监听模式的套接字描述符 int backlog //同时能够处理连接请求的数目 如:5,10 5.5函数的返回值 成功:返回0 失败:返回-1 6.用于接收客户端连接的API函数accept() 6.1头文件 #include <sys/types.h> #include <sys/socket.h> 6.2函数的功能 等待接收一个来自客户端的TCP connectiont请求 6.3函数的原型 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 6.4函数的参数 int sockfd //一个监听的套接字文件描述符 struct sockaddr *addr //网络地址结构体的指针,用来保存客服端的地址信息的。 socklen_t *addrlen //网络地址结构体长度类型的指针,用来保存网络地址结构体的长度 6.5函数的返回值 成功:返回与该客户端的连接套接字描述符,后续与该客户端的数据交互都是通过 该 连接套接字描述符 失败:返回-1 7.用于TCP client去连接TCP server 的API函数 connect() 7.1头文件 #include <sys/types.h> #include <sys/socket.h> 7.2函数的功能 用于TCP的客户端去连接TCP的服务端 7.3函数的原型 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 7.4函数的参数 int sockfd //套接字文件描述符 const struct sockaddr *addr //对方的地址,TCP server的地址 socklen_t addrlen //第二个参数指向的地址结构体的长度 7.5函数的返回值 成功返回0 失败返回-1
任务要求
- 自己写一个客户端 再写一个服务器
- 能进行简单的数据交互
代码实现
- 服务端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<linux/socket.h>
#include <unistd.h>
int main()
{
//1.socket:创建一个套接字
int socketfd0 = socket(AF_INET, SOCK_STREAM, 0);
if(socketfd0 == -1)
{
perror("creat socketfd0 fail\n");
return -1;
}
//2.bind:把一个套接字和网络地址 绑定在一起。
struct sockaddr_in a;
a.sin_family = AF_INET;
a.sin_port = htons(10086);
a.sin_addr.s_addr = inet_addr("192.168.0.110");
int num = bind(socketfd0, (struct sockaddr *)&a,sizeof(struct sockaddr));
if(num == -1)
{
perror("bind address fail\n");
return -1;
}
//3.listen:让套接字进入一个“监听模式”
num = listen(socketfd0, 5);
if(num == -1)
{
perror("set listen fail\n");
return -1;
}
//4.accept:接收客户端的连接
struct sockaddr ad;
socklen_t adl;
int txfd = accept(socketfd0, &ad, &adl); //等待客户端连接,如果没有客户端连接
if(txfd == -1) //程序会停止在这里等待(即程序阻塞在这里)
{
perror("accept fail\n");
}
//5.write
char buf[6] = "hello";
num = write(txfd,buf,5);
if(num == -1)
{
perror("write txfd fail\n");
}
//read
//6.close:"四路挥手"
close(txfd);
}
-
客户端
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <linux/socket.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { //1.socket: int sockefd = socket(AF_INET, SOCK_STREAM, 0); if(sockefd == -1) { perror("creat socket fail\n"); return -1; } //2.bind:可要可不要 //3.connect: 主动与TCP Server建立连接 //“三次握手” struct sockaddr_in a; //(struct sockaddr *)&a a.sin_family = AF_INET; a.sin_port = htons(10520); a.sin_addr.s_addr = inet_addr("112.74.113.206"); int num = connect(sockefd, (struct sockaddr *)&a,sizeof(struct sockaddr)); if(num == -1) { perror("connect fail\n"); return -1; } //4.write // read char buf[2] ={0,1};//门 开 char buf1[2] = {8,8}; while(1) { num = write(sockefd,buf,2); if(num == -1) { perror("write fail\n"); return -1; } sleep(1); num = read(sockefd,buf1,2); if(num == -1) { perror("read sockefd fail\n"); } printf("buf1[0] is %d buf1[1] is %d\n",buf1[0],buf1[1]); sleep(5); } //5.close close(sockefd); return 0; }