Linux C 网络编程基础

IP地址

IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。

分类::

IPV4  -- 4个字节
IPV6  -- 16个字节

IPV4

IPv4的姿势

192.168.101.5  --->点分十进制

IPv4的组成

网络地址 + 主机地址
主机地址:不能全部为0或者全部为1
					--->全部为0 ---网络id号
					--->全部为1 ---广播地址

IPv4的分类

A类: 1个字节网络地址 + 3个字节主机地址
	网络地址:以0开头
	取值范围:
	00000000.0.0.1 	~ 01111111.255.255.254
	0.0.0.1 ~ 127.255.255.254
			
B类: 2个字节网络地址 + 2个字节主机地址
	网络地址:以10开头
	取值范围:
		10000000.0.0.1 ~ 10111111.255.255.254
		128.0.0.1 ~ 191.255.255.254
			
C类: 3个字节网络地址 + 1个字节主机地址
	网络地址:以110开头
	取值范围:
		11000000.0.0.1 ~ 11011111.255.255.254
		192.0.0.1 ~ 223.255.255.254
			---->我们的IP : 192.168.101.5
		
D类: 4个字节网络地址 + 0个字节主机地址   ---> 多播(组播)
	网络地址:以1110开头
	取值范围:
		11100000.0.0.0 ~ 11101111.255.255.255
		224.0.0.0 ~ 239.255.255.255
		
E类: 网络地址: 11110开头 ,待留后用

补充: tracert www.baidu.com ----- 查看网关

子网掩码

概念

用于减少IP浪费,细化IP分类,判断若干个网络是否在同一局域网内的机制

表现形式

网络地址+主机地址 
网络地址全部为1   主机地址全部为0

姿势

255.255.255.0  ----> 3个字节的网络地址  1个字节主机地址  
[192.168.101.5/24]  ----> /24 代表 前 24位  子网掩码的 网络地址

判断是否在同一网络下的规则

ip地址 & 子网掩码  ----->  网络id号  
如果网络id号相同,则在同一网络下
例:
    192.168.101.5  & 255.255.255.0 ----> 192.168.101.0
    192.168.101.10 & 255.255.255.0 ----> 192.168.101.0
    ---->就说 192.168.101.5 和 192.168.101.10 在同一网络下 

将主机地址分出一部分作为 子网地址

255.255.255.1110000
192.168.101.0011000 & 255.255.255.1110000 ----> 192.168.101.0010000
192.168.101.0111000 & 255.255.255.1110000 ----> 192.168.101.0110000
称: 192.168.101.24 与 192.168.101.56 不在同一网络

网关

概念:
网关又称网间连接器、协议转换器。默认网关在网络层以上实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关的结构也和路由器类似,不同的是互连层。网关既可以用于广域网互连,也可以用于局域网互连。其实质是一个网络通向另外一个网络的IP地址

计算机网络体系结构

OSI 模型 OSI架构(七层)

    --------------
	|   应用层   |
	--------------
	|   表示层   |
	--------------
	|   会话层   |
	--------------
	|   传输层   |
	--------------
	|   网络层   |
	--------------
	| 数据链路层 |
	--------------
	|   物理层   |
	--------------

TCP/IP架构(四层)

    --------------
	|   应用层   | 
	--------------
	|   传输层   |
	--------------
	|   网际层   |
	--------------
	| 网络接口层 |
	--------------

原理体系架构(五层)

--------------
|   应用层   |	通过应用进程的交互实现网络应用
--------------
|   传输层   |	解决进程间基于网络通信的问题   (TCP UDP 端口对端口)
--------------
|   网络层   |	解决在多个网络上传输的问题     (IP地址 寻找路线)
--------------
| 数据链路层 |	解决在一个网络上的传输问题
--------------
|   物理层   |	解决使用何种信号表示比特的问题

端口号:
2个字节 65536
用户使用时端口在5001-65536之间,建议范围内越大越好

数据发送的整个流程

数据
应用层 :HTTP+数据        (HTTP报文)   
传输层 :TCP+HTTP+数据  	 (TCP报文)
网络层 :IP+TCP+HTTP+数据 (IP报文)
数据链路层: ETH+IP+TCP+HTTP+数据+ETH (帧)
物理层:前导码+帧  将帧看成比特流 

路由器转发过程

物理层 :    去掉前导码   	---》 帧
数据链路层: 去掉帧头帧尾	---》 IP数据报
网络层: 分析IP数据报确认路线重新打包IP数据报
数据链路层: 添加帧头帧尾 ---》 帧
物理层 :    前导码+帧  将帧看成比特流

数据接受的整个流程

物理层 :   去掉前导码   	---》 帧
数据链路层:去掉帧头帧尾	---》 IP数据报
网络层:    去掉IP协议头   ---》 TCP+HTTP+数据
传输层:    去掉端口协议头 ---》 HTTP+数据
应用层: 	 去掉协议头     ---》 数据

ARP请求: 通过IP地址得到物理地址
RARP请求:通过物理地址 得到 IP地址

IP数据报的生存时间

TTL : 跳   次数      8

TCP数据报

URG : 紧急数据
SYN表示建立连接,
FIN表示关闭连接,
ACK表示响应,
PSH表示有 DATA数据传输,没有缓冲,直接发送给应用层
RST表示连接重置

传输层

TCP UDP 差异

TCP:事先必须建立连接,数据传输稳定,可靠,不丢包
UDP:不需要连接,不可靠,可能会丢包

TCP三次握手与四次挥手

三次握手:  1. 客户端给服务器发送SYN连接请求
			2. 服务器给客户回复了确认序列ACK,并发起SYN连接请求
			3. 客户端给服务器回复了确认序列ACK
	
四次挥手:	1. 客户端给服务器发送FIN断开请求,并回复确认序列ACK
			2. 服务器给客户端回复了确认序列ACK
			3. 服务器给客户端发送FIN断开请求,并回复确认序列ACK
			4. 客户端给服务器回复确认序列ACK 		

Socket 编程

服务器

创建Socket

*socket:
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>	
int socket(int domain, int type, int protocol);
解释:
	创建socket套接字 
参数:
	domain : 协议
		AF_UNIX, AF_LOCAL   Local communication              unix(7)
		AF_INET             IPv4 Internet protocols          ip(7)
		AF_INET6            IPv6 Internet protocols          ipv6(7)
	type: 
		SOCK_STREAM :流式套接字   (TCP)
		SOCK_DGRAM  : 数据报套接字 (UDP)
		SOCK_RAW    : 原始套接字
	protocol : 0
返回值:
	int :成功返回socket文件描述符
		  失败返回-1 并设置错误码 

绑定IP PORT

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
解释:
	绑定IP和PORT
参数:
	sockfd :sock套接字
	addr   :struct sockaddr *
			struct sockaddr {
				sa_family_t sa_family;		//unsigned short
				char        sa_data[14];
			}//  加起来 16个字节
	addrlen : addr的长度
返回值:
	成功返回0 
	失败返回-1 并设置错误码 
			
grep struct\ sockaddr_in\ {/usr/src/linux-hwe-5.4-headers-5.4.0-122/include/* -rn          */

IPV4:
	#define __SOCK_SIZE__   16              /* sizeof(struct sockaddr)*/
	
	struct sockaddr_in {
		__kernel_sa_family_t  sin_family;     /* Address family  */
		__be16                sin_port;       /* Port number */
		struct in_addr        sin_addr;       /* Internet address */
		                    /* Pad to size of `struct sockaddr'. */
		unsigned char         __pad[__SOCK_SIZE__ - sizeof(short int) -
					sizeof(unsigned short int) - sizeof(struct in_addr)]    ;
	};

	struct in_addr {
		__be32  s_addr;
	};

			
	IPV6:
		struct sockaddr_in6
			
	本地:
		struct sockaddr_un

获取IP和端口号

端口号   
    htons: 主机数据转网络数据  host to net short  
    ntohs: 网络数据转主机数据  net to host short 
获取IP
    #include <arpa/inet.h>
    uint16_t htons(uint16_t hostshort);
	uint16_t ntohs(uint16_t netshort);

	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <arpa/inet.h>
	int inet_aton(const char *cp, struct in_addr *inp);
	主机地址转网络地址
	cp : 点分十进制ip地址
    inp : struct in_addr

	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <arpa/inet.h>
	char *inet_ntoa(struct in_addr in);
	网络地址转主机地址

	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <arpa/inet.h>
	in_addr_t inet_addr(const char *cp);
	主机地址转网络地址
	cp : 点分十进制ip地址 
	in_addr_t :网络数据类型的ip

INADDR_ANY; //自动获取到IP

监听

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
*解释:
	监听,将主动连接变成被动连接
参数:	
	sockfd : sock套接字
	backlog: 允许同一瞬间同时连接服务器的客户数量
返回值:
	成功返回0 
	失败返回-1 并设置错误码 

阻塞等待客户端的连接

accept:
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:
	sockfd : sock套接字
	addr   :  struct sockaddr * 客户端的数据(IP和PORT)
	addrlen:  addr的长度指针  socklen_t *
返回值:
	成功返回文件描述符
	失败返回-1 并设置错误码

客户端

连接服务器

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数:
	sockfd : sock套接字
	addr   : 服务器的IP和PORT
	addrlen: addr的长度
返回值:
	成功返回0 
	失败返回-1 并设置错误码 
	
recv:接收
	#include <sys/types.h>
	#include <sys/socket.h>
	ssize_t recv(int sockfd, void *buf, size_t len, int flags);
	参数:	
    	sockfd : 文件描述符(套接字)
    	buf : 读取数据存储的位置
    	len : 长度
    	flags :0  阻塞  
	返回值:
    	成功返回得到的字节数
    	失败返回-1 并设置error
    	掉线则返回0

send:发送 
	#include <sys/types.h>
	#include <sys/socket.h>
 	ssize_t send(int sockfd, const void *buf, size_t len, int flags);
	参数:	
    	sockfd : 文件描述符(套接字)
    	buf : 读取数据存储的位置
    	len : 长度
    	flags :0  阻塞  
	返回值:
    	成功返回发送的字节数
    	失败返回-1 并设置error

补充代码:

服务器:

#include <stdio.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

#define PORT  12345
#define IP 	  "192.168.101.5"	

struct sockaddr_in client;

void *readMsg (void *arg)
{
	int fd = *(int *)arg;
	char buf[100];
	int n = 10;
	int ret;
	while(1){
		bzero(buf,sizeof(buf));
		ret = recv(fd,buf,sizeof(buf),0);
		if(ret>0){
			printf("客户说<ip:%s>说:%s\n",inet_ntoa(client.sin_addr),buf);
			n = 10;
		}else if(ret==0){
			printf("客户掉线了\n");
			close(fd);
			exit(-1);
		}else{
			while(n--)
				continue;
			close(fd);
			exit(-1);
		}
	}
}

int main(void)
{
	//创建socket套接字 
	int sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(sockfd<0){
		perror("socket error");
		exit(-1);
	}

	int on = 1;
	setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	
	//绑定IP和PORT
	struct sockaddr_in server;
	server.sin_family = AF_INET;
	server.sin_port = htons(PORT);
	server.sin_addr.s_addr = INADDR_ANY; //自动获取到IP
//	server.sin_addr.s_addr = inet_addr(IP);
	//inet_aton(IP,&server.sin_addr);
	int ret = bind(sockfd,(struct sockaddr *)&server,sizeof(server));
	if(ret){
		perror("bind error");
		exit(-1);
	}
	
	//监听,将主动连接变成被动连接
	ret = listen(sockfd,30);
	if(ret){
		perror("listen error");
		exit(-1);
	}
	
	//阻塞等待客户端的连接
	unsigned int len = sizeof(client);
	int fd = accept(sockfd,(struct sockaddr *)&client,&len);
	if(fd<0){
		perror("accept error");
		exit(-1);
	}
	printf("%d服务器已上线\n",fd);
	printf("客户IP:%s\n",inet_ntoa(client.sin_addr));
	printf("客户PORT:%hu\n",ntohs(client.sin_port));
	
	pthread_t thread;
	pthread_create(&thread,NULL,readMsg,&fd);
	pthread_detach(thread);
	
	char buf[100];
	while(1){
		bzero(buf,sizeof(buf));
		scanf("%s",buf);
		send(fd,buf,strlen(buf),0);
	}
	
	close(fd);
	close(sockfd);

	
	return 0;
}


客户端:

#include <stdio.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

void *readMsg (void *arg)
{
	int fd = *(int *)arg;
	char buf[100];
	int n = 10;
	int ret;
	while(1){
		bzero(buf,sizeof(buf));
		ret = recv(fd,buf,sizeof(buf),0);
		if(ret>0){
			printf("服务器说:%s\n",buf);
			n = 10;
		}else if(ret==0){
			printf("服务器掉线了\n");
			close(fd);
			exit(-1);
		}else{
			while(n--)
				continue;
			close(fd);
			exit(-1);
		}
	}
}

int main(int argc,char *argv[])
{
	if(argc!=3){
		printf("usage:%s <ip> <port>\n",argv[0]);
		exit(-1);
	}
	
	//创建socket套接字 
	int sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(sockfd<0){
		perror("socket error");
		exit(-1);
	}
	
	//连接服务器	
	struct sockaddr_in server;
	server.sin_family = AF_INET;
	server.sin_port = htons(atoi(argv[2]));
	server.sin_addr.s_addr = inet_addr(argv[1]);;
	int ret = connect(sockfd,(struct sockaddr *)&server,sizeof(server));
	if(ret){
		perror("connect error");
		exit(-1);
	}
	
	
	pthread_t thread;
	pthread_create(&thread,NULL,readMsg,&sockfd);
	pthread_detach(thread);
	
	char buf[100];
	while(1){
		bzero(buf,sizeof(buf));
		scanf("%s",buf);
		send(sockfd,buf,strlen(buf),0);
	}
	
	close(sockfd);

	
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一门linux下c++通讯架构实战课程,针对c/c++语言已经掌握的很熟并希望进一步深造以将来用c++在linux下从事网络通讯领域/网络服务器的开发和架构工作。这门课程学习难度颇高但也有着极其优渥的薪水(最少30K月薪,最高可达60-80K月薪),这门课程,会先从nginx源码的分析和讲解开始,逐步开始书写属于自己的高性能服务器框架代码,完善个人代码库,这些,将会是您日后能取得高薪的重要筹码。本课程原计划带着大家逐行写代码,但因为代码实在过于复杂和精细,带着写代码可能会造成每节课至少要4~5小时的超长时间,所以老师会在课前先写好代码,主要的时间花费在逐行讲解这些代码上,这一点望同学们周知。如果你觉得非要老师领着写代码才行的话,老师会觉得你当前可能学习本门课程会比较吃力,请不要购买本课程,以免听不懂课程并给老师差评,差评也会非常影响老师课程的销售并造成其他同学的误解。 这门课程要求您具备下面的技能:(1)对c/c++语言掌握的非常熟练,语言本身已经不是继续学习的障碍,并不要求您一定熟悉网络或者linux;(2)对网络通讯架构领域有兴趣、勇于挑战这个高难度的开发领域并期望用大量的付出换取高薪;在这门课程中,实现了一个完整的项目,其中包括通讯框架和业务逻辑框架,浓缩总结起来包括如下几点:(1)项目本身是一个极完整的多线程高并发的服务器程序;(2)按照包头包体格式正确的接收客户端发送过来的数据包, 完美解决收包时的数据粘包问题;(3)根据收到的包的不同来执行不同的业务处理逻辑;(4)把业务处理产生的结果数据包正确返回给客户端;本项目用到的主要开发技术和特色包括:(1)epoll高并发通讯技术,用到的触发模式是epoll中的水平触发模式【LT】;(2)自己写了一套线程池来处理业务逻辑,调用适当的业务逻辑处理函数处理业务并返回给客户端处理结果;(3)线程之间的同步技术包括互斥量,信号量等等;(4)连接池中连接的延迟回收技术,这是整个项目中的精华技术,极大程度上消除诸多导致服务器程序工作不稳定的因素;(5)专门处理数据发送的一整套数据发送逻辑以及对应的发送线程;(6)其他次要技术,包括信号、日志打印、fork()子进程、守护进程等等;
linux C语言 网络编程教程及源码 一、网络应用层编程 1、Linux网络编程01——网络协议入门 2、Linux网络编程02——无连接和面向连接的区别 3、Linux网络编程03——字节序和地址转换 4、Linux网络编程04——套接字 5、Linux网络编程05——C/S与B/S架构的区别 6、Linux网络编程06——UDP协议编程 7、Linux网络编程07——广播 8、Linux网络编程08——多播 9、Linux网络编程09——TCP编程之客户端 10、Linux网络编程10——TCP编程之服务器 11、Linux网络编程11——tcp、udp迭代服务器 12、Linux网络编程12——tcp三次握手、四次挥手 13、Linux网络编程13——connect()、listen()和accept()三者之间的关系 14、Linux网络编程14——I/O复用之select详解 15、Linux网络编程15——I/O复用之poll详解 16、Linux网络编程16——I/O复用之epoll详解 17、Linux网络编程17——tcp并发服务器(多进程) 18、Linux网络编程18——tcp并发服务器(多线程) 19、Linux网络编程——tcp高效并发服务器(select实现) 20、Linux网络编程——tcp高效并发服务器(poll实现) 21、Linux网络编程——tcp高效并发服务器(epoll实现) 二、网络底层编程(黑客模式) 1、Linux网络编程1——啥叫原始套接字 2、Linux网络编程2——原始套接字编程 3、Linux网络编程3——原始套接字实例:MAC头分析 4、Linux网络编程4——原始套接字实例:MAC地址扫描器 5、Linux网络编程5——IP数据报格式详解 6、Linux网络编程6——TCP、UDP数据包格式详解 7、Linux网络编程7——原始套接字实例:发送UDP数据包 8、Linux网络编程8——libpcap详解 9、Linux网络编程9——libnet详解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值