C语言网络编程

网络编程概念

网络:计算机与计算机相连;
互联网:网络与网络相连;
因特网:全球规模最大,用户最多的互联网,采用TCP/IP协议栈;

应用层:业务数据的组织;
传输层:进程间通信;
网络层:主机间的通信;
数据链路层:网口间的通信
物理层:物理介质;

IP地址:因特网核心网每台主机的唯一身份标识,其组成为:1.四字节整型,2.点分十进制字符串,3.域名;
端口号:某台主机上面,某个进程的身份标识;
其组成为:两字节整型;
MAC地址,物理地址,网卡地址:每张网卡的全球唯一的身份标识。
Socket:插排,插孔,插头的统称;
因特网Socket地址:IP地址+端口号;

TCP传输:面向连接的,有序的,可靠的,流式传输;
UDP传输:非面向连接的,不可靠的,无序的,报式传输,支持组播与广播

TCP传输的C语言代码模板

客户端:

int sockfd = -1;
struct socketaddr_in servaddr;
int ret = 0;
//创建一个用于因特网通信的操作引擎
//并且将引擎对象的地址填入进程的描述符数组中
sockfd = socket(AF_INET,SOCK_STREAM,0);
//填写服务端socket地址
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = honts(????);
inet_aton("????",&seraddr.sin_addr);
ret = connect(sockfd,(struct sockadd*)&servaddr,sizeof(servaddr));
if(ret < 0){
//出错处理
}
//根据程序功能逻辑进行发送或者接收数据
//read  write send recv
close(sockfd);
sockfd = -1;

服务端

int servfd;
int datafd;
int ret = 0;
struct socketaddr_in servaddr;
sockfd = socket(AF_INET,SOCK_STREAM,0);
//填写服务器自身的socket地址
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(????);
inet_aton("?????",&servaddr.sin_addr);
ret = bind(servfd,(struct sockaddr*)&servaddr,sizoeof(servaddr));
ret = listen(servfd,???);//将主动套接字变为被动套接字;
if(ret < 0){
//出错处理
}
while(1){
	datafd = accept(servfd,NULL,NULL);
	if(datafd < 0){
		if(errno == EINTR){
			continue;
		}
		else{
			break;
		}
	}
	//使用datafd与对应客户端进行数据收发
}
close(servfd);
servfd = -1;

TCP服务端如何管理连接请求

1.TCP服务端采用两个队列来管理客户端的连接请求:
未完成的连接请求队列:存放正在进行三路握手链接请求;
已完成的连接请求队列:存放已经完成三路握手的连接请求;

C语言网络编程_第1张图片
ps:每个节点代表一个连接请求,节点在收到某个客户端发来的连接请求时被创建;

建立连接的过程如下:
1.服务端收到某个客户端发过来的连接请求,就创建一个节点代表该连接请求
2.将该节点入队到未完成的连接请求队列中;
3.服务端组织好,针对该连接请求的回应,以及自己的连接请求发送给客户端;
4.等待客户端发来自身连接请求的回应;
5.一旦收到客户端发来的自身连接请求回应,表示与该客户端连接已建立成功,就将该连接请求对应的节点从未完成连接请求队列中出队,并入队到已完成的连接请求队列中;

listen函数的功能
1.变主动套接字为被动套接字----第一个形参变成被动套接字后才会:
(1).接收客户端的连接请求
(2).创建两个空队列,用于处理连接请求
2.决定两个队列的最大节点数----第二个形参;

accept函数的功能
1.检查已完成连接请求是否为空:则本函数阻塞等待到不空;
2.不空则出队第一个连接请求对应的节点,并创建一个用于与对应客户端进行数据传输用的通信引擎对象,并且将该引擎对象的地址填入服务器进程的描述符数组;

TCP服务器的并发

TCP服务端都需要同时为多个用户端提供服务
三种方案
1.多进程并发:
每次accept正常返回,就创建一个子进程,让该子进程专门使用本次返回的文件描述符与对应的客户端进行数据交互,为了避免子进程的僵死态,while(1)循环前调用:signal(SIGCHILD,SIG_IGN);
2.多线程并发:
每次accept正常返回,就创建一个新的线程,让该线程专门的使用本次返回的描述符与对应的客户端进行数据交互,为了避免新线程的僵死态,在新线程的入口函数的开头调用pthread_detach(pthread_self());
3.多路复用:
一种可以同时监控多个描述符状态的机制------并不是真正意义上的并发
将被动套接字和每次accept返回的套接字组合起来,交给一个函数去统一监控,该监控函数一旦发现某个描述符关联的通信通道有数据可读的时候,则该函数返回,然后服务端使用对应的描述符接收客户端发过来的数据,为对应的客户端提供一次数据服务;
ps:采用多路复用的服务器,要求服务端对客户端每次发过来的数据处理都很快。

TCP连接的长久保持问题

1.通过心跳机制来解决
心跳机制:
方案一:采用协议栈自带的心跳机制 setsockopt来激活该心跳功能,并设置心跳机制工作过程中的参数;
方案二:应用层协议中添加一种与业务能力无关的数据—心跳包,让连接上的每隔多久就进行一次心跳包数据的发送

TCP接收和发送超时设置方案:
1.调用setsockopt函数来设置接收,发送的超时时长
2.借助于多路复用
3.alarm函数----不推荐

UDP传输

接收数据时,如果某次发送方发送N个字节的数据,而接收方只接收了M个字节,则N-M个字节的剩余数据被丢弃—报式传输
支持的两种方式:
1.非连接的客户端
客户端:sendto发送数据 ,recvfrom接收数据
服务端:sendto发送数据, recvfrom接收数据
2.连接的客户端—定向传输
数据交互前客户端调用一下connect,确保客户端只与对应的服务器进行数据交互
客户端:connect send/write发送数据 recv/read接收数据
服务端:sendto发送数据 recvfrom接收数据

UDP广播 UDP组播

你可能感兴趣的:(网络,c语言,服务器)