网络编程复习
1.学习网络编程的目的?
使用套接字通信,来实现跨主机多进程之间的通讯
2.OSI体系结构和TCP/IP体系结构
OSI体系结构:
应用层:提供网络应用程序和用户之间的接口,实现应用程序和用户的通讯
DNS,Telnet,FTP,TFTP,HTTP,ModbusTCP工业总线协议等
表示层:负责数据的格式化和转换,使得数据能够在不同系统能够表示和解释。负责数据的加密解密,编码解码
会话层:负责建立连接,管理,终止会话,实现通讯
传输层:负责端到端的数据传输,确保数据的可靠传输和错误恢复(TCP UDP)
网络层:负责数据的路由和转发,实现不同网络的数据传输。ip寻址
数据链路层:将数据包转化为帧,并进行帧的处理。MAC寻址
物理层:负责传输比特流,定义物理介质和电气特性,以及硬件信息。
TCP/IP
应用层,传输层,网络层,网络接口和物理层
3.三次握手
1.客户端发送SYN报文(seq=j)给服务器
2.服务器接收到SYN报文后,回复客户端ACK(ack=j+1)并发送SYN包(seq=k)询问下一次什么时候发送
3.客户端接收到后回复ACK(ack=k+1)给服务器
4.四次挥手
1.客户端向服务器发送FIN报文,客户端进入FIN_WAIT1状态
2.服务器接收到后发送ACK报文进入CLOSE_WAIT状态,客户端进入FIN_WAIT2状态
3.服务器完成ACK报文发送后,发送FIN报文给客户端,服务器进入LAST_ACK状态
4.客户端接收到FIN报文后进入TIME_WAIT状态,等待一段时间(2MSL),然后关闭,服务器接收到后也关闭
5.字节序函数的使用
#define IP "192.168.1.1"
int main(int argc, const char *argv[])
{
in_addr_t kkk = inet_addr(IP);//将IP地址转为网络IP
printf("%x\n",kkk);
struct in_addr mmm;
mmm.s_addr = kkk;//将网络IP放入结构体成员中
char *p = inet_ntoa(mmm);//将网络IP转为点分十进制IP
printf("%s\n",p);
return 0;
}
6.何时不需要进行主机字节序和网络字节序的转换
1、单字节整数不需要转换
2、字符串也不需要转换
(只有多字节整数才需要转换)
7.LAN和WAN
LAN:局域网,覆盖小,速度快,延时低
WAN:广域网,覆盖大,速度慢,延时高
8.IPV4地址的划分和分类
IP地址=网络号+主机号
分类:
A类: 1.0.0.0-----127.255.255.255 网络号1字节
B类:128.0.0.0---191.255.255.255 网络号2字节
C类:192.0.0.0---223.255.255.255 网络号3字节
D类(组播):224.0.0.0--239.255.255.255 网络号4字节
E类(实验室或者政府特别机构):240.0.0.0--255.255.255.255 网络号4字节
地址范围的起始,看第一个字节(8位)的前四位
A:0000 0.0.0.0 和127.0.0.0规定好不用的 127.0.0.0是回环地址,做循环测试用的.
B:10
C:110
D:1110
E:1111
9.引入子网掩码的IP
IP=网络号+子网号+主机号
子网网段由 ip地址&子网掩码组成
默认子网掩码:子网掩码就是某类网络的 网络号全是1,主机号全是0的值。
子网网段的个数 = 2^(子网掩码中1的个数)
子网网段下的主机个数 = 2^(子网中0的个数)
10.TCP服务器客户端
//服务器
#define IP "192.168.1.2"
#define PORT 8888
#define BACKLOG 30
int main()
{
int oldfd=socket(AF_INET,SOCK_STREAM,0);
if(oldfd==-1)
{
perror("socket");
return -1;
}
struct sockaddr_in server={
.sin_family=AF_INET,
.sin_port=htons(PORT),
.sin_addr.s_addr=inet_addr(IP),
};
if(bind(oldfd,(struct sockaddr*)&server,sizeof(server))==-1)
{
perror("bind");
return -1;
}
if(listen(oldfd,BACKLOG)==-1)
{
perror("listen");
return -1;
}
struct sockaddr_in client;
socklen_t client_len=sizeof(client);
int newfd=accept(oldfd,(struct sockaddr*)&client,&client_len);
if(newfd==-1)
{
perror("accept");
return -1;
}
printf("%s发来连接请求\n",inet_ntoa(client.sin_addr));
char buff[1024];
while(1)
{
memset(buff,0,sizeof(buff));
int len=recv(newfd,buff,sizeof(buff),0);
if(len==0)
{
//客户端下线
}
strcat(buff,"111");
send(newfd,buff,sizeof(buff),0);
}
close(oldfd);
close(newfd);
return 0;
}
//客户端
#define IP "192.168.1.2"
#define PORT 8888
int main()
{
int oldfd=socket(AF_INET,SOCK_STREAM,0);
if(oldfd==-1)
{
perror("socket");
return -1;
}
struct sockaddr_in server={
.sin_family=AF_INET,
.sin_port=htons(PORT),
.sin_addr.s_addr=inet_addr(IP),
};
socklen_t server_len=sizeof(server);
if(connect(oldfd,(struct sockaddr*)&server,&server_len)==-1)
{
perror("bind");
return -1;
}
char buff[1024];
while(1)
{
fgets(buff, sizeof(buff), stdin);
buff[strlen(buff)-1]='\0';
send(oldfd,buff,sizeof(buff),0);
int len=recv(newfd,buff,sizeof(buff),0);
if(len==0)
{
//服务器退出
break;
}
}
close(oldfd);
return 0;
}
11.UDP服务器客户端
//服务器
#define IP "192.168.1.2"
#define PORT 8888
int main()
{
int oldfd=socket(AF_INET,SOCK_DGRAM,0);
if(oldfd==-1)
{
perror("socket");
return -1;
}
struct sockaddr_in server={
.sin_family=AF_INET,
.sin_port=htons(PORT),
.sin_addr.s_addr=inet_addr(IP),
};
if(bind(oldfd,(struct sockaddr*)&server,sizeof(server))==-1)
{
perror("bind");
return -1;
}
struct sockaddr_in client;
socklen_t client_len=sizeof(client);
char buff[1024];
while(1)
{
memset(buff,0,sizeof(buff));
int len=recvfrom(oldfd,buff,sizeof(buff),(struct sockaddr*)&client,&client_len);
if (len < 0) {
perror("recvfrom");
break;
}
strcat(buff,"111");
sendto(oldfd,buff,sizeof(buff),0,(struct sockaddr*)&client,client_len);
}
close(oldfd);
return 0;
}
//客户端
#define IP "192.168.1.2"
#define PORT 8888
int main()
{
int oldfd=socket(AF_INET,SOCK_DGRAM,0);
if(oldfd==-1)
{
perror("socket");
return -1;
}
struct sockaddr_in server={
.sin_family=AF_INET,
.sin_port=htons(PORT),
.sin_addr.s_addr=inet_addr(IP),
};
socklen_t server_len=sizeof(server);
char buff[1024];
while(1)
{
fgets(buff, sizeof(buff), stdin);
buff[strlen(buff)-1]='\0';
sendto(oldfd,buff,sizeof(buff),0,(struct sockaddr*)&client,client_len);
memset(buff, 0, sizeof(buff));
int len=recvfrom(newfd,buff,sizeof(buff),0,(struct sockaddr*)&client,&client_len);
if (len < 0) {
perror("recvfrom");
break;
}
}
close(oldfd);
return 0;
}
12.单播广播组播
单播:一对一通信
广播:一对多通信
//设置套接字允许广播
int n=1;
if(setsockopt(oldfd,SOL_SOCKET,SO_BROADCAST,&n,sizeof(n))==-1)
{
perror("setsockopt");
return -1;
}
组播:一对多通信,加入多播组之间的通信
D类ip 224.0.0.0 -- 239.255.255.255
#define ZIP "224.1.2.3"
#define IP "192.168.60.66"
#define PORT 7777
struct ip_mreqn recv={
.imr_multiaddr.s_addr=inet_addr(ZIP),//组播组IP
.imr_address.s_addr=inet_addr(IP),//本机IP
.imr_ifindex=2,//ens33网卡索引号
};
if(setsockopt(oldfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&recv,sizeof(recv))==-1)
{
perror("setsockopt");
return -1;
}
13.IO多路复用
select
fd_set readfds,temp;//定义两个集合存放描述符
int maxfd = oldfd;//保留最大的描述符
FD_ZERO(&readfds);
FD_SET(0,&readfds);
FD_SET(oldfd,&readfds);
while(1)
{
temp=readfds;
int res=select(2,&temp,NULL,NULL,NULL);
if(res==0)
{
//超时
continue;
}
if(res==-1)
{
perror("select");
}
for(int i=0;i<=maxfd;i++)
{
if(!FDISSET(i,&temp))//没有发生操作就下一个
{
continue;
}
if(i==oldfd)
{
int newfd=accept(i,(struct sockaddr *)&client,&client_len);
FD_SET(newfd,&readfds);
maxfd=newfd>maxfd?newfd:maxfd;
}
else
{
char buff[1024];
memset(buff,0,sizeof(buff));
int len = recv(i,buff,sizeof(buff),0);//0:阻塞发送 MSG_DONTWAIT:非阻塞
if(len==0)
{
close(i);
FD_CLR(i,&readfds);
if(maxfd==i)
{
maxfd--;
}
break;
}
printf("%s\n",buff);
fgets(buff,sizeof(buff),stdin);
send(i,buff,sizeof(buff),0);
}
}
}
poll
struct pollfd fds[2];
fds[0].fd=0;
fds[0].events=POLLIN;
fds[1].fd=oldfd;
fds[1].events=POLLIN;
while(1)
{
int res=poll(fds,2,-1);
if(res==0)
{
//超时
}
if(res==-1)
{
perror("poll");
return -1;
}
if(fds[1].revents==POLLIN)
{
//oldfd产生了事件
}
if(fds[0].revents==POLLIN)
{
//标准输入流产生了事件
}
}
epoll
监听的最大的文件描述符没有个数限制
14.SQL数据库
1.创建表
create table if not exist stu (id int,name char);
2.插入
insert into stu (id,name) values(1,'ww')
alter table stu add column score int;//增加列
3.删除
drop table stu;//删除表
delete from stu where id=1;
delete from stu; 删除表格中的所有数据;
4.更改
update stu set id=5 where name="张三";
5.查找
select * from stu;
select id,name from stu;
int callback(void *arg,int n,char **msgtext ,char **msgtable)
{
int i,j;
for(i = 0;i<n;i++)
{
printf("%s\t",*(msgtable+i));//打印表头
}
printf("\n");
for(j = 0;j<n;j++)
{
printf("%s\t",*(msgtable+j));//打印一行数据
}
printf("\n");
return 0;
}
snprintf(sql,sizeof(sql),"select * from stu1 where name=\"%s\";",name);
if(sqlite3_exec(ppDb,sql,callback,NULL,&errmsg)==1)
{
perror("sqlite3_exec");
printf("错误信息:%s\n",sqlite3_errmsg(ppDb));
printf("错误码:%d\t出错行是:%d\n",sqlite3_errcode(ppDb),__LINE__);
}
char **m;
char *errqqq = NULL;
int hang,lie;
snprintf(sql,sizeof(sql),"%s","select * from stu1;");
res = sqlite3_get_table(ppDb,sql,&m,&hang,&lie,&errqqq);
if(res!=0)
{
perror("sqlite3_get_table");
printf("错误信息:%s\n",errqqq);
}
//get_table函数执行到此,参数全部被赋值
//循环输出信息
int i,j;
printf("\n\n\n");
for(i = 0;i<=hang;i++)
{
for(j = 0;j<lie;j++)
{
printf("%s\t",*(m+i*lie+j));
}
printf("\n");
}
sqlite3_free_table(m);//释放指向数据库表格的指针
sqlite3_close(ppDb);//关闭数据库句柄
6.拷贝
从a中拷贝所有数据到b中:
create table b as select * from a;
从a中拷贝指定字段到b中:
create table b as select 字段,字段,字段 from a;