UNIX_C 高级编程<六>
来源:互联网 发布:淘宝行架 编辑:程序博客网 时间:2024/05/29 21:33
网络编程
七层网络模型 `
为了实现数据在网络中的传递,ISO将网络协议从逻辑上划分一下七层
应用层 — 主要用于将数据交给应用程序,如:QQ等
表示层 — 主要用于按照统一的格式进程数据的封装等
会话层 — 主要用于控制对话的开始和结束等
传输层 — 主要用于进行数据的错误检查和重新排序等
网络层 — 主要用于选择具体的网络协议,再次封装和传输
数据链路层 — 主要用于将数据转换为高低电平号等
物理层 — 主要指交换机等物理设备等
常用的网络协议
TCP协议 —— 传输控制协议,是一种面向链接的协议,类似打电话
UDP协议 —— 用户数据报协议,是一种非面向链接协议,类似写信
IP协议 —— 互联网协议,是上述两种协议的底层协议
IP地址和子网掩码(重点)
IP地址 —— 本质就是互联网中的唯一地址标识
IP地址本质上就是由32位二进制组成的整数(ipv4),由128位二进制组成的整数(ipv6)
日常生活中采用点分十进制表示法来描述IP地址,即将没8位二进制转换成一个十进制的
+整数,不同的十进制整数之间使用小数点分隔;
为了便于IP地址的管理,将IP地址分为两部分:网络地址+主机地址,根据网络地址和主机
+地址的不同分为一下4类IP地址:
A类:0 + 7位网络地址+24为主机地址
B类:10+14位网络地址+16位主机地址
C类:110+21位网络地址+8位主机地址
D类:1110+28位多播地址
查看IP地址:
windows系统ipconfig/all
linux系统ifconfig
子网掩码
子网验码 —用于划分IP地址中网络地址和主机地址,具体划分方法为:IP地址&子网验码
IP地址:172. 30 .4 .130
子网验码:255.255.255.0 &
-------------------------------
网络地址:172.30 .4 .0
端口号和字节序
IP地址 — 定位到具体某一台设备
端口号 — 定位到设备中的具体某一个进程
端口好本质就是unsigned short 类型,范围是0~65535,其中0~1024已经被系统占用,因此建议从1025开始使用
字节序
小端系统:低位字节的数据存放在低位内存地址
大端系统:低位字节的数据存放在高位内存地址
一般性原则:
一般来说,将所有发送到网络中的多字节整数先转换成为网络字节序在发送,而将所有从网络中接收到的多字节整数先转换为主机字节序再解析,而网络字节序本上就是大端系统的字节序
基于socket的一对一通信模型
socket - 逻辑通信载体;
通信模型
主机A:
1.创建socket,使用socket函数;
2.准备通信地址,使用结构体类型;
3.绑定socket和通信地址,使用bind函数;
4.进行通信,使用read/write函数;
5.关闭socket,使用close函数
主机B:
1.创建socket,使用socket函数;
2.准备通信地址,使用主机A的通信地址;
3.链接socket和通信地址,使用connect函数;
4.进行通信,使用read/write函数;
5.关闭socket,使用close函数
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
1、int sockfd = socket(int domain,int type, int protocol);
参 1:域/地址族,决定是本地通信还是网络通信
AF_UNIX/AF_LOCAL - 实现本地通信(在同一个主机)
AF_INET - 实现基于ipv4的网络通信(不同主机)
AF_INET6
参 2:通信类型,决定了通信的方式
SOCK_STREAM - 表示提供可靠的,有序,双向的,面向链接的字节流通信方式也就是基于tcp协议的通信
SOCK_DGRAM - 表示提供不可靠的,非面向链接的数据包通信的方式,也就是基于udp协议
参 3:用于指定特殊协议,默认给0即可
返回:成功返回socket的描述符,失败返回-1
功能:主要用于创建用于交流的通信点;
2、通信地址的数据类型
a.通用的通信地址类型
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
} —— 该结构体主要用于函数的形参类型,很少定义变量
b.基于本地通信的数据类型
#include<sys/un.h>
struct sockaddr_un{
sa_family_t sun_family//地址族 AF_UNIX
char sun_path[]//socket文件的路径名strcpy(addr.sun_path,"a.sock");
};
c.基于网络通信的数据类型
#include <netinet/in.h>
the sockaddr_in{
sa_family_t sin_family //协议族
in_port_t sin_port //端口
struct in_addr sin_addr //ip地址
};
struct in_addr{
in_addr_t s_addr //整数类型的IP地址
};
3、int bind(int sockfd, const structsockaddr *addr, socklen_t addrlen);
参 1:socket的描述符,socket函数的返回值
参 2:结构体指针,可能传入结构体体变量的地址,可能需要做类型转换
参 3:通信地址的大小,使用sizeof计算即可
功能:主要用于绑定socket和通信地址;
4、int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参 1:socket的描述符,socket函数的返回值
参 2:结构体指针,可能传入结构体体变量的地址,可能需要做类型转换
参 3:通信地址的大小,使用sizeof计算即可
功能:主要用于链接socket和通信地址,参数和返回值与bind相同
1 //实现基于socket的本地通信
2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <unistd.h> 7 #include <sys/types.h> 8 #include <sys/socket.h> 9 #include <sys/un.h>10 11 int main(void)12 {13 14 //1.创建socket,使用socket函数15 int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);16 if( -1 == sockfd )17 {18 perror("socket");19 exit(-1);20 }21 printf("创建socket成功\n");22 //2.准备通信地址,使用结构体23 struct sockaddr_un addr;24 addr.sun_family= AF_UNIX;25 strcpy( addr.sun_path,"a.sock");26 //3.绑定socket和通信地址,使用bind函数27 28 int res = bind(sockfd,(const struct sockaddr *) (&addr), sizeof(addr));29 if( -1 == res )30 {31 perror("bind");32 exit(-1);33 }34 printf("绑定socket和通信地址成功\n");35 //4.进行通信,使用read/write函数36 char buf[100] = {0};37 38 res = read(sockfd, buf, sizeof(buf));39 if(-1 == res )40 {41 perror("read");42 exit(-1);43 }44 printf("读取到的数据是:%s, 数据大小是:%d\n", buf, res);45 46 //5.关闭socket.使用close47 48 res = close(sockfd);49 if(-1 == res )50 {51 perror("close");52 exit(-1);53 }54 55 printf("成功关闭socket\n");56
基于socket的一对一通信
字节序转换的相关函数
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); —— 32位主机字节序到网络字节序转换
uint16_t htons(uint16_thostshort); —— 16位主机字节序到网络字节序转换
uint32_t ntohl(uint32_t netlong); —— 32为网络字节序到主机字节序转换
uint16_t ntohs(uint16_t netshort); —— 16位网络字节序到主机字节序转换
IP地址的转换函数
in_addr_t inet_addr(const char *cp); —— 主要用于将字符串形式的IP地址转换成为整数类型
char *inet_ntoa(struct in_addr in); —— 主要用于将结构体类型的IP地址转换成字符串类型;
//实现基于socket网络通信 2 //bind读取端的实现 3 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <unistd.h> 7 #include <sys/types.h> 8 #include <sys/socket.h> 9 #include <netinet/in.h>10 #include <arpa/inet.h>11 12 int main(void)13 {14 15 //1.创建socket,使用socket函数16 17 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);18 if( -1 == sockfd)19 {20 perror("socket error");21 exit(-1);22 }23 24 printf("创建socket成功\n");25 26 //2.准备通信地址,使用结构体类型27 28 struct sockaddr_in addr;29 30 addr.sin_family = AF_INET;31 addr.sin_port = htons(8888);32 addr.sin_addr.s_addr =inet_addr( "172.30.4.127" );33 34 //3.绑定socket和通信地址,使用bind函数35 36 int res = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr) );37 if( -1 == res )38 {39 perror("bind error");40 exit(-1);41 }42 43 printf("绑定socket和通信地址成功\n");44 45 char buf[100] = {0};46 47 //4.进行通信,使用read函数48 49 res = read(sockfd, buf, sizeof(buf));50 if(-1 == res )51 {52 perror("read ");53 exit(-1);54 }55 56 printf("成功读取数据的内容是:%s, 数据大小为:%d\n", buf, res);57 //5.关闭socket。使用close函数58 59 res = close(sockfd);60 if( -1 == res )61 {62 perror("close");63 exit(-1);64 }65 66 printf("成功关闭socket\n");67 68 return 0;69 }
通信模型
服务器:
1、创建socket,使用socket函数
2、准备通信地址,使用结构体类型
3、绑定socket和通信地址,使用bind函数
4、监听,使用listen函数
5、响应客户端的连接请求,使用accept函数
6、进行通信,使用recv/send函数
7、关闭socket, 使用close函数
客户端
1、创建socket,使用socket函数
2、准备通信地址,使用服务器的地址
3、绑定socket和通信地址,使用connect函数
4、进行通信,使用recv/send函数
5、关闭socket, 使用close函数
相关函数的解析
int sockfd = socket(int domain, int type,int protocol);
参 1:域/地址族,决定是本地通信还是网络通信
AF_UNIX/AF_LOCAL- 实现本地通信(在同一个主机)
AF_INET - 实现基于ipv4的网络通信(不同主机)
AF_INET6
参 2:通信类型,决定了通信的方式
SOCK_STREAM - 表示提供可靠的,有序,双向的,面向链接的字节流通信方式也就是基于tcp协议的通信
SOCK_DGRAM - 表示提供不可靠的,非面向链接的数据包通信的方式,也就是基于udp协议
参 3:用于指定特殊协议,默认给0即可
返回:成功返回socket的描述符,失败返回-1
功能:主要用于创建用于交流的通信点;
通信地址的数据类型
a.通用的通信地址类型
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
} —— 该结构体主要用于函数的形参类型,很少定义变量
b.基于本地通信的数据类型
#include<sys/un.h>
struct sockaddr_un{
sa_family_t sun_family //地址族AF_UNIX
char sun_path[] //socket文件的路径名strcpy(addr.sun_path,"a.sock");
};
c.基于网络通信的数据类型
#include<netinet/in.h>
the sockaddr_in{
sa_family_t sin_family //协议族
in_port_t sin_port //端口
struct in_addr sin_addr //ip地址
};
struct in_addr{
in_addr_t s_addr //整数类型的IP地址
};
int listen(int sockfd, int backlog);
参一:socket描述符,socket函数的返回值
参二:用于指定请求但未响应的队列的最大长度
功能:主要用于将参数sockfd所指向的socket标记为被动的socket,所谓的被动socket就是专门用于响应
即将到来的连接请求,不再用于通信(用于接待的socket);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参一:socket描述符,socket函数的返回值
参二:结构体指针,用于带出客户端的通信地址
参三:指针类型,用于带出通信地址的大小
返回:成功返回新的socket描述符,失败返回-1
功能:主要用于响应客户端的链接请求,主要用于从监听状态socket上悬而未决队列中提取第一个链接请求
+并进行处理,处理的方式就是创建一个新的链接成功的socket进行通信
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参一:socket描述符,accept函数的返回值
参二:缓冲区首地址,用于保存接收到的数据
参三:期望接收的数据大小
参四:接收的标志,默认给0即可
返回:成功返回实际接收数据的大小,失败返回-1
功能:主要用于接收参数指定socket中的内容
ssize_tsend(int sockfd, const void *buf, size_t len, int flags);
参一:socket描述符,传递主动socket的描述符
参二:缓冲区首地址
参三:期望接收的数据大小
参四:发送的标志,默认给0即可
返回:成功返回实际发送数据的大小,失败返回-1
功能:主要用于向指定的socket发送指定的内容
52 //解决地址被占用的问题
53
54 intreuseaddr = 1;
55
56 setsockopt(sockfd,SOL_SOCKET, SO_REUSEADDR, &reuseaddr,sizeof(int));
1 //实现基于tcp协议模式的一对多程序_服务端
2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <unistd.h> 7 #include <sys/types.h> 8 #include <sys/socket.h> 9 #include <netinet/in.h>10 #include <arpa/inet.h>11 #include <signal.h>12 13 //定义全局变量记录socket描述符14 15 int sockfd;16 17 void fa(int signum )18 {19 printf("正在关闭服务器.请稍后...\n");20 sleep(3);21 int res = close(sockfd);22 if(-1 == res )23 {24 perror("close");25 exit(-1);26 }27 28 printf("成功关闭服务器\n");29 exit(0); //终止当前进程30 }31 32 int main(void)33 {34 35 //1.创建socket,使用socket函数36 37 sockfd = socket(AF_INET, SOCK_STREAM, 0);38 if(-1 == sockfd )39 {41 exit(-1);42 }43 44 printf("socket创建成功!\n");45 //2.准备通信地址,使用结构体类型46 47 struct sockaddr_in addr;48 addr.sin_family = AF_INET;49 addr.sin_port = htons(8888);50 addr.sin_addr.s_addr = inet_addr("172.30.4.127");51 52 //解决地址被占用的问题53 54 int reuseaddr = 1;55 56 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,sizeof(int));57 58 //3.绑定socket和通信地址,使用bind函数59 int res = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));60 if(-1 == res )61 {62 perror("bind");63 exit(-1);64 }65 66 printf("绑定成功!\n");67 //4.监听,使用listen函数68 69 res = listen(sockfd, 100);70 if(-1 == res)71 {72 perror("listen");73 exit(-1);74 }75 76 printf("监听成功\n");77 78 //使用信号关闭服务器79 printf("关闭服务器,请按CTRL+C..\n");80 if(SIG_ERR == signal(SIGINT, fa))81 {82 perror("signal");83 exit(-1);84 }85 86 //5.不断地响应客户端的链接要求,accept87 88 while(1)89 {90 struct sockaddr_in recv_addr;91 socklen_t len = sizeof(recv_addr);92 int fd = accept(sockfd, (struct sockaddr *)&recv_addr, &len);93 if(-1 == fd)94 {95 perror("accept");96 exit(-1);97 }98 99 char * ip = inet_ntoa(recv_addr.sin_addr);00 printf("客户端%s链接成功..\n", ip);01 02 //创建子进程为当前客户端服务03 pid_t pid = fork();04 if( -1 == pid )05 {06 perror("fork");07 exit(-1);08 }09 10 //子进程11 if( 0 == pid)12 {13 //设置子进程对信号SIGINT默认处理14 if( SIG_ERR == signal(SIGINT, SIG_DFL))15 {16 perror("signal");17 exit(-1);18 }19 20 //关闭接待/被动的socket21 res = close(sockfd);22 if(-1 == res )23 {24 perror("close");25 exit(-1);26 }27 //6.针对每个客户端可以不断地进行通信28 29 30 while(1)31 {32 char buf[100] ={0};33 34 res = recv(fd, buf, sizeof(buf), 0);35 36 if( -1 == res )37 {38 perror("recv");39 exit(1);40 }41 42 //当客户端发来bye表示下线43 if( strcmp(buf, "bye") == 0 )44 {45 printf("客户端%s已下线!", ip);46 break;47 }48 49 printf("客户端%s发来的消息是:%s\n", ip, buf);50 51 printf("发送的消息为:");52 fgets(buf, sizeof(buf), stdin);53 54 if( strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf)-2] != '\n' )55 {56 scanf("%*[^\n]");57 scanf("%*c");58 }59 60 res = send(fd, buf, strlen(buf), 0);61 62 if( -1 == res )63 {64 perror("send");65 exit(-1);66 }67 }68 69 //执行break之后跳到了这里70 71 //关闭用于通信的fd72 res = close(fd);73 if(-1 == res )74 {75 perror("close");76 exit(-1);77 }78 79 //终止子进程80 exit(0);81 }82 83 //父进程关闭通信fd85 res = close(fd);86 if(-1 == res )87 {88 perror("close");89 exit(-1);90 }93 }95 return 0;96 }
- UNIX_C 高级编程<六>
- UNIX_C 高级编程<一>
- UNIX_C 高级编程<二>
- UNIX_C 高级编程<三>
- UNIX_C 高级编程<四>
- UNIX_C 高级编程<五>
- UNIX_C 高级编程<七>
- unix_c++
- linux高级编程六Makefile
- ASP 3.0高级编程(六)
- C#高级编程六十四天----并行扩展
- 《Unix环境高级编程》总结(六)
- 老赵弱弱学习——unix环境高级编程(六)
- 高级编程语言的发展历程(六)
- Unix环境高级编程学习笔记(六) 信号机制
- (六)Linux网络编程--6. 高级套接字函数
- Python学习 (六 面向对象高级编程)
- 《UNIX环境高级编程》六系统数据文件和信息读书笔记
- linux 监控之CACTI
- Delphi StringGrid使用全书
- 应用程序从后台线程修改自动布局引擎导致奇怪的崩溃
- Activity task问题(一)现象:Activity task栈顺序,而非Activity在task中的顺序,是和最后启动的Activity有关的
- bundle文件单例对象的创建
- UNIX_C 高级编程<六>
- 【Java】 enum(枚举)使用详解 + 总结
- RCNN, Fast RCNN, Faster RCNN
- PyGobject(五十五)布局容器之Toolbar
- 字典数Trie树详解及其应用
- Android ADB批处理脚本
- leetcode Meeting Rooms II
- 在mac系统安装Apache Tomcat的详细步骤
- 理解RxJava的线程模型