linux系统编程和网络编程,linux网络高级编程
一、Linux网络概述
Linux为用户提供了完善而强大的网络功能。
1.完善的内置网络。其他操作系统不包含与内核结合如此紧密的网络部分。
2.Linux免费提供大量支持互联网的软件。互联网是在Unix领域建立并繁荣起来的。这方面用Linux还是挺方便的。用户可以使用Linux通过互联网与世界上的其他人交流。
3.用户可以通过一些Linux命令传输内部信息或文件。
4.支持远程访问
5.安全可靠,采用多种安全技术措施为用户提供安全保障。
网络模型
第一部分是网络层协议:互联网协议(IP)、网络控制消息协议(ICMP)和地址解析协议(ARP)。
第二部分是传输层协议:传输控制协议(TCP)(面向连接的可靠)和用户数据报协议(UDP)(不可靠未连接)。
第三部分是应用层协议:Telnet、FTP和TFTP、简单文件传输协议(SMTP)和域名服务(DNS)。
协议封装
使用wireshark进行数据包捕获分析
逐层封装:以太网IP TCP
以太网-IP- TCP- HTTP
以太网数据包
互联网协议
IP的功能:数据传输、寻址、路由、数据报文分段。
主要目的是为数据输入输出网络提供基本算法,为高层协议提供无连接传输服务。这意味着在将数据提交给接收站点之前,IP不会在传输站点和接收站点之间建立对话。它只封装和传输数据,不向发送方或接收方报告数据包状态,也不处理遇到的故障。
它由协议头和协议数据组成。
TCP协议
是一种重要的传输层协议,其目的是允许与网络上的其他节点可靠地交换数据。它可以提供端口号解码,以识别主机应用程序并完成可靠的数据传输。
TCP有一个严格的内置错误检查算法来确保数据的完整性。
TCP是一种面向字节的顺序协议,这意味着数据包中的每个字节都分配有一个序列号,每个数据包都分配有一个序列号。
UDP协议
它也是传输层协议,是一种无连接、不可靠的传输服务。在接收数据时,它不向发送方提供确认信息,不提供输入包的顺序,在出现包丢失或包重复的情况下,也不会向发送方发送错误消息。因为它在执行函数时开销低,所以执行速度比TCP快。
二、Linux网络编程基础
窝
Linux中的网络编程是通过Socket实现的,Socket是一种文件描述符。
三种类型
1.流式套接字(SOCK_STREAM)
它可以提供可靠的、面向连接的通信流,并且它使用TCP协议,这保证了数据传输的正确性和顺序性。
2.数据报套接字(SOCK_DGRAM)
定义了无连接服务。数据通过独立的消息传输,乱序,可靠,无错。它使用数据报协议UDP。
3.原始套接字(SOCK_RAW)
允许使用IP协议,主要用于测试新的网络协议等。
网络地址
想要的是
{
u _ short sa _ family
char sa _ data[14];
} sa_family:协议族,形式为‘AF _ XXX’,如AF_INET(IP协议族)
Sa _ data: 14字节特定协议地址
地址结构
另一个结构
地址转换
IP地址通常用带点的数字表示,而结构体in_addr中love使用的IP地址用32位整数表示。
int inet_aton(const char *cp,struct in_addr *inp)
char * inet_ntoa(结构输入地址输入)
前者是32位整数,后者是32位数字——字符串。
字节顺序
在同一网络上使用Big endian,低位字节先传输。
当内部字节存储顺序与网络字节顺序不同时,需要进行转换。
为什么,示例:
转换:
Htons:将无符号短类型从主机顺序转换为网络顺序(发送)
Htonl:将无符号长整型从主机顺序转换为网络顺序(发送)
Ntohs:将无符号短类型从网络序列转换为主机序列(接收)
Ntohl:将无符号长整型从网络序列转换为主机序列(接收)
和IP主机名
套接字编程功能
插座:创建一个窝
绑定:用于绑定互联网协议(互联网协议)地址和端口号到窝
连接:用于与服务器建立连接
听着:设置服务器能处理的最大连接要求
接受:用来等待来自服务端的窝连接请求
发送:发送数据
建议:接收数据
三、基于三氯苯酚
服务器
客户端
通信模型
示例代码tcp_server.c
#包含标准库
#包含标准视频
#包含错误号h
#包含字符串。h
#包含netdb.h
#包含sys/types.h
#包含netinet/in.h
#包含sys/socket.h
#包括arpa/inet.h
#定义端口号3333
int main(int argc,char *argv[])
{
int sockfd,new _ fd
结构sockaddr _ in server _ addr
客户端地址中的结构sockaddr _ in
int sin _ size
int nbytes
茶缓冲区[1024];
/* 服务器端开始建立套接字描述符*/
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)//AF _ INET:IP v4;套接字流:TCP
{
fprintf(stderr,套接字错误:%s\n\a ,strerror(errno));
出口(1);
}
/* 服务器端填充套接字地址结构*/
bzero( server_addr,sizeof(struct sockaddr _ in));//初始化,置0
服务器地址。sin _家庭=AF _ INET//互联网
服务器地址。sin _ addr。s _ addr=htonl(在addr _ ANY中);//(将本机器上的长的数据转化为网络上的长的数据)和任何主机通信//INADDR_ANY表示可以接收任意互联网协议(互联网协议)地址的数据,即绑定到所有的互联网协议(互联网协议)
//server _ addr。sin _ addr。s _ addr=inet _ addr( 192。168 .1 .1 );//用于绑定到一个固定IP,inet_addr用于把数字加格式的互联网协议(互联网协议的缩写)转化为整形互联网协议(互联网协议的缩写)
server_addr.sin_port=htons(端口号);//(将本机器上的短的数据转化为网络上的短的数据)端口号
/* 捆绑套接字描述符到互联网协议(互联网协议)地址*/
if(bind(sockfd,(struct sockaddr *)( server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,绑定错误:%s\n\a ,strerror(errno));
出口(1);
}
/* 设置允许连接的最大客户端数*/
if(listen(sockfd,5)==-1)
{
fprintf(stderr,侦听错误:%s\n\a ,strerror(errno));
出口(1);
}
while(1)
{
/* 服务器阻塞,直到客户程序建立连接*/
sin _ size=sizeof(struct sockaddr _ in);
if((new_fd=accept(sockfd,(struct sockaddr *)( client_addr),sin_size))==-1)
{
fprintf(stderr,接受错误:%s\n\a ,strerror(errno));
出口(1);
}
fprintf(stderr,服务器从%s获取连接\n ,inet _ ntoa(client _ addr。sin _ addr));//将网络地址转换成。字符串
if((nbytes=read(new_fd,buffer,1024))==-1)
{
fprintf(stderr,读取错误:%s\n ,strerror(errno));
出口(1);
}
buffer[nbytes]= \ 0 ;
printf(服务器接收到%s\n ,缓冲区);
/* 这个通讯已经结束*/
close(new _ FD);
/* 循环下一个*/
}
/* 结束通讯*/
关闭(sockfd);
退出(0);
} 示例代码tcp_client.c
#包含标准库
#包含标准视频
#包含错误号h
#包含字符串。h
#包含netdb.h
#包含sys/types.h
#包含netinet/in.h
#包含sys/socket.h
#包括arpa/inet.h
#定义端口号3333
int main(int argc,char *argv[])
{
int sockfd
茶缓冲区[1024];
结构sockaddr _ in server _ addr
结构主机*主机
/* 使用主机名查询宿主名字*/
如果(argc!=2)
{
fprintf(stderr,用法:%s主机名\a\n ,argv[0]);
出口(1);
}
if((host=gethostbyname(argv[1])==NULL)
{
fprintf(stderr, Gethostname error \ n );
出口(1);
}
/* 客户程序开始建立套接字描述符*/
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)//AF _ INET:Internet;套接字流:TCP
{
fprintf(stderr,套接字错误:%s\a\n ,strerror(errno));
出口(1);
}
/* 客户程序填充服务端的资料*/
bzero( server_addr,sizeof(server _ addr));//初始化,置0
服务器地址。sin _家庭=AF _ INET//IPV4
server_addr.sin_port=htons(端口号);//(将本机器上的短的数据转化为网络上的短的数据)端口号
服务器地址。sin _ addr=*((struct in _ addr *)host-h _ addr);//IP地址
/* 客户程序发起连接请求*/
if(connect(sockfd,(struct sockaddr *)( server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,连接错误:%s\a\n ,strerror(errno));
出口(1);
}
/* 连接成功了*/
printf(请输入char:\ n );
/* 发送数据*/
fgets(buffer,1024,stdin);
write(sockfd,buffer,strlen(buffer));
/* 结束通讯*/
关闭(sockfd);
退出(0);
} 运行结果:客户端
[gyy @本地主机TCP]$ gcc TCP _ client。转交TCP _客户端
[gyy@localhost TCP]$ ./TCP _客户端192.168.1.30
请输入字符:
12345运行结果:服务器
[gyy @ localhost TCP]$ gcc TCP _ server。c-o TCP服务器
[gyy@localhost TCP]$ ./tcp_server
服务器从192.168.1.30获取连接
服务器收到12345代码分析:服务器三次阻塞:第一次等待连接,第二次等待读,第三次客户端发送完成后断开连接服务器等待连接
四、基于用户数据报协议(用户数据报协议)
客户端
通信模型
示例代码udp_server.c
#包含标准库
#包含标准视频
#包含错误号h
#包含字符串。h
#包括unistd.h
#包含netdb.h
#包含sys/socket.h
#包含netinet/in.h
#包含sys/types.h
#包括arpa/inet.h
#定义服务器端口8888
#定义最大消息大小1024
void udps_respon(int sockfd)
{
结构sockaddr _ in地址
int addrlen,n;
char MSG[MAX _ MSG _ SIZE];
while(1)
{ /* 从网络上读,并写到网络上*/
bzero(msg,sizeof(msg));//初始化,清零
addrlen=sizeof(struct sockaddr);
n=recvfrom(sockfd,msg,MAX_MSG_SIZE,0,(struct sockaddr*) addr,addrlen);//从客户端接收消息
msg[n]=0;
/* 显示服务端已经收到了信息*/
fprintf(标准输出,服务器已收到“%s”,消息);//显示消息
}
}
int main(void)
{
int sockfd
结构sockaddr _ in地址
/* 服务器端开始建立窝描述符*/
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd 0)
{
fprintf(stderr,套接字错误:%s\n ,strerror(errno));
出口(1);
}
/* 服务器端填充套接字地址结构*/
bzero( addr,sizeof(struct sockaddr _ in));
地址. sin _ family=AF _ INET
地址。sin _ addr。s _ addr=htonl(在addr _ ANY中);
地址。sin _ PORT=htons(SERVER _ PORT);
/* 捆绑套接字描述符*/
if(bind(sockfd,(struct sockaddr *) addr,sizeof(struct sockaddr_in)) 0)
{
fprintf(stderr,绑定错误:%s\n ,strerror(errno));
出口(1);
}
UDPS _ respon(sockfd);//进行读写操作
关闭(sockfd);
} 示例代码udp_client.c
#包含标准库
#包含标准视频
#包含错误号h
#包含字符串。h
#包括unistd.h
#包含netdb.h
#包含sys/socket.h
#包含netinet/in.h
#包含sys/types.h
#包括arpa/inet.h
#定义服务器端口8888
#定义MAX_BUF_SIZE 1024
void udpc_requ(int sockfd,const struct sockaddr_in *addr,int len)
{
char buff[MAX _ BUF _ SIZE];
int n;
while(1)
{ /* 从键盘读入,写到服务端*/
printf(请输入char:\ n );
fgets(buffer,MAX_BUF_SIZE,stdin);
sendto(sockfd,buffer,strlen(buffer),0,addr,len);
bzero(buffer,MAX _ BUF _ SIZE);
}
}
int main(int argc,char **argv)
{
int sockfd
结构sockaddr _ in地址
如果(argc!=2)
{
fprintf(stderr,用法:%s server_ip\n ,argv[0]);
出口(1);
}
/* 建立套接字描述符*/
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd 0)
{
fprintf(stderr,套接字错误:%s\n ,strerror(errno));
出口(1);
}
/* 填充服务端的资料*/
bzero( addr,sizeof(struct sockaddr _ in));
地址. sin _ family=AF _ INET
地址。sin _ PORT=htons(SERVER _ PORT);
if(inet_aton(argv[1],addr.sin_addr) 0) /*inet_aton函数用于把字符串型的互联网协议(互联网协议)地址转化成网络2进制数字*/
{
fprintf(stderr, Ip错误:%s\n ,strerror(errno));
出口(1);
}
udpc_requ(sockfd,addr,sizeof(struct sockaddr _ in));//进行读写操作
关闭(sockfd);
} 运行结果:客户端
[gyy @ localhost UDP]$ gcc UDP _ client。转交UDP _客户端
[gyy@localhost UDP]$ ./UDP _客户端192.168.1.30
请输入字符:
你好
请输入字符:
世界
请输入字符:运行结果:服务器
[gyy @ localhost UDP]$ gcc UDP _ server。转交UDP _服务器
[gyy@localhost UDP]$ ./udp_server
服务器收到你好
服务器已接收世界五、服务器模型在网络程序里,一般来说都是许多客户对应一个服务器,两种服务器模型
循环服务器、并发服务器
三氯苯酚循环服务器
三氯苯酚循环服务器一次只能处理一个客户端的请求,只有在这个客户的所有请求都满足后,服务器才可以继续后面的请求。这样如果有一个客户端占住了服务器不放时,其它的客户机都不能工作了,因此三氯苯酚服务器一般很少用循环服务器模型
示例代码:tcp_server_fork.c
#包含标准库
#包含标准视频
#包含错误号h
#包含字符串。h
#包含netdb.h
#包含sys/types.h
#包含netinet/in.h
#包含sys/socket.h
#包括arpa/inet.h
#定义我的端口3333
int main(int argc,char **argv)
{
int listen_fd,accept _ fd
客户端地址中的结构sockaddr _ in
int n;
if((listen_fd=socket(AF_INET,SOCK_STREAM,0)) 0)
{
printf(套接字错误:%s\n\a ,strerror(errno));
出口(1);
}
bzero( client_addr,sizeof(struct sockaddr _ in));
客户端_地址。罪恶_家庭=AF _ INET
客户端地址。sin _ PORT=htons(MY _ PORT);
客户端地址。sin _ addr。s _ addr=htonl(在addr _ ANY中);
n=1;
/* 如果服务器终止后,服务器可以第二次快速启动而不用等待一段时间*/
setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,n,sizeof(int));
if(bind(listen_fd,(struct sockaddr *) client_addr,sizeof(client_addr)) 0)
{
printf(绑定错误:%s\n\a ,strerror(errno));
出口(1);
}
listen(listen_fd,5);
while(1)
{
accept_fd=accept(listen_fd,NULL,NULL);
if((accept_fd 0) (errno==EINTR))
继续;
else if(accept_fd 0)
{
printf(接受错误:%s\n\a ,strerror(errno));
继续;
}
if((n=fork())==0)
{
//printf( OK \ n );
/* 子进程处理客户端的连接*/
茶缓冲区[1024];
关闭(listen _ FD);
n=read(accept_fd,buffer,1024);
write(accept_fd,buffer,n);
printf(接收:%s\n ,缓冲区);
close(accept _ FD);
退出(0);
}
else if(n 0)
printf(Fork Error:%s\n\a ,strerror(errno));
close(accept _ FD);
}
} 示例代码:tcp_client.c
#包含标准库
#包含标准视频
#包含错误号h
#包含字符串。h
#包含netdb.h
#包含sys/types.h
#包含netinet/in.h
#包含sys/socket.h
#包括arpa/inet.h
#定义端口号3333
int main(int argc,char *argv[])
{
int sockfd
茶缓冲区[1024];
结构sockaddr _ in server _ addr
结构主机*主机
/* 使用主机名查询宿主名字*/
如果(argc!=2)
{
fprintf(stderr,用法:%s主机名\a\n ,argv[0]);
出口(1);
}
if((host=gethostbyname(argv[1])==NULL)
{
fprintf(stderr, Gethostname error \ n );
出口(1);
}
/* 客户程序开始建立套接字描述符*/
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)//AF _ INET:Internet;套接字流:TCP
{
fprintf(stderr,套接字错误:%s\a\n ,strerror(errno));
出口(1);
}
/* 客户程序填充服务端的资料*/
bzero( server_addr,sizeof(server _ addr));//初始化,置0
服务器地址。sin _家庭=AF _ INET//IPV4
server_addr.sin_port=htons(端口号);//(将本机器上的短的数据转化为网络上的短的数据)端口号
服务器地址。sin _ addr=*((struct in _ addr *)host-h _ addr);//IP地址
/* 客户程序发起连接请求*/
if(connect(sockfd,(struct sockaddr *)( server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,连接错误:%s\a\n ,strerror(errno));
出口(1);
}
/* 连接成功了*/
printf(请输入char:\ n );
/* 发送数据*/
fgets(buffer,1024,stdin);
write(sockfd,buffer,strlen(buffer));
/* 结束通讯*/
关闭(sockfd);
退出(0);
}
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。