【本文谢绝转载原文来自http://990487026.blog.51cto.com】
《大纲》 Linux统系统开发10 Socket API编程1 OSI 七层模型 TCP/IP四层模型 数据报封装格式 IP数据报封装 TCP数据报封装 UDP数据报封装 TCP链接与断开 netstat 命令 大端小端 TCP服务器最小模型 服务器,客户端最小模型 服务端为客户端转换字符大小写 模型
OSI七层模型
1.物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后再转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。
2.数据链路层:定义了如何让格式化数据以进行传输,以及如何让控制对物理介质的访问。这一层通常还提供错误检测和纠正,以确保数据的可靠传输。
3.网络层:在位于不同地理位置的网络中的两个主机系统之间提供连接和路径选择。Internet的发展使得从世界各站点访问信息的用户数大大增加,而网络层正是管理这种连接的层。
4.传输层:定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。 主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。
5.会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)。
6.表示层:可确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。例如,PC程序与另一台计算机进行通信,其中一台计算机使用扩展二一十进制交换码(EBCDIC),而另一台则使用美国信息交换标准码(ASCII)来表示相同的字符。如有必要,表示层会通过使用一种通格式来实现多种数据格式之间的转换。
7.应用层:是最靠近用户的OSI层。这一层为用户的应用程序(例如电子邮件、文件传输和终端仿真)提供网络服务。
TCP/IP四层模型
一般开发程序员讨论最多的是TCP/IP模型
以太网封装格式
ARP数据报格式
IP数据报格式
TCP数据报格式
UDP数据报格式
TCP状态转换图
TCP连接与断开
数据进入协议栈时封装过程
socketAPI
大端小端
"大端"和"小端"表示多字节值的哪一端存储在该值的起始地址处;
小端存储在起始地址处,即是小端字节序;
大端存储在起始地址处,即是大端字节序;
或者说:
1.小端法(Little-Endian)就是低位字节排放在内存的低地址端(即该值的起始地址),
高位字节排放在内存的高地址端;
2.大端法(Big-Endian)就是高位字节排放在内存的低地址端(即该值的起始地址),
低位字节排放在内存的高地址端; 举个简单的例子,对于整型数据0x12345678,
它在大端法和小端法的系统中,各自的存放方式:
查看最大连接数
chunli@ubuntu:~/linux_c/network$ cat /proc/sys/net/ipv4/tcp_max_syn_backlog 128 chunli@ubuntu:~/linux_c/network$
服务器端最小模型
chunli@ubuntu:~/linux_c/network$ cat server.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <arpa/inet.h> int main(void) { struct sockaddr_in serveraddr; struct sockaddr_in clientaddr; int socketfd; int clientfd; int addrlen; int port; char ipstr[128]; //1.socket socketfd = socket(AF_INET,SOCK_STREAM,0); //建立TCP //2.bind bzero(&serveraddr,sizeof(serveraddr)); serveraddr.sin_family = AF_INET; //地址族协议IPV4 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址 serveraddr.sin_port = htons(8000); //端口 bind(socketfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); //3.listen listen(socketfd,128); while(1) { //4.appept addrlen = sizeof(clientaddr); clientfd = accept(socketfd,(struct sockaddr*)&clientaddr,&addrlen);//发返回客户端socket //输出客户端Ip地址 和端口号 inet_ntop(AF_INET,&clientaddr.sin_addr.s_addr,ipstr,sizeof(ipstr));//ip数字转字符 port = ntohs(clientaddr.sin_port); //大端转小端 printf("client ip %s ,port:%d \n",ipstr,port); //处理客户请求 //5再见 close(clientfd); } close(socketfd); return 0; } chunli@ubuntu:~/linux_c/network$ 窗口1,编译运行: chunli@ubuntu:~/linux_c/network$ gcc server.c && ./a.out 窗口2,可以看得出来,8000端口已被监听 chunli@ubuntu:~/linux_c/network$ netstat -tln 激活Internet连接 (仅服务器) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.1.1:53 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN tcp6 0 0 :::22 :::* LISTEN chunli@ubuntu:~/linux_c/network$ chunli@ubuntu:~/linux_c/network$ nc localhost 8000 chunli@ubuntu:~/linux_c/network$ nc localhost 8000 chunli@ubuntu:~/linux_c/network$ nc localhost 8000 chunli@ubuntu:~/linux_c/network$ nc localhost 8000 窗口1,显示信息: chunli@ubuntu:~/linux_c/network$ gcc server.c && ./a.out client ip 127.0.0.1 ,port:57434 client ip 127.0.0.1 ,port:57436 client ip 127.0.0.1 ,port:57438 client ip 127.0.0.1 ,port:57440
服务器,客户端最小模型
chunli@ubuntu:~/linux_c/network$ cat server.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <arpa/inet.h> int main(void) { struct sockaddr_in serveraddr; struct sockaddr_in clientaddr; int socketfd; int clientfd; int addrlen; int port; char ipstr[128]; //1.socket socketfd = socket(AF_INET,SOCK_STREAM,0); //建立TCP //2.bind bzero(&serveraddr,sizeof(serveraddr)); serveraddr.sin_family = AF_INET; //地址族协议IPV4 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址 serveraddr.sin_port = htons(8000); //端口 bind(socketfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); //3.listen listen(socketfd,128); while(1) { //4.appept addrlen = sizeof(clientaddr); clientfd = accept(socketfd,(struct sockaddr*)&clientaddr,&addrlen);//发返回客户端socket //输出客户端Ip地址 和端口号 inet_ntop(AF_INET,&clientaddr.sin_addr.s_addr,ipstr,sizeof(ipstr));//ip数字转字符 port = ntohs(clientaddr.sin_port); //大端转小端 printf("client ip %s ,port:%d \n",ipstr,port); //处理客户请求 //5再见 close(clientfd); } close(socketfd); return 0; } chunli@ubuntu:~/linux_c/network$ gcc -o server server.c && ./server 可以看得出来,8000端口已被监听: chunli@ubuntu:~/linux_c/network$ netstat -ant 激活Internet连接 (服务器和已建立连接的) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.1.1:53 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN tcp 0 0 11.11.11.3:22 11.11.11.2:56953 ESTABLISHED tcp 0 52 11.11.11.3:22 11.11.11.2:56956 ESTABLISHED tcp 0 0 11.11.11.3:22 11.11.11.2:56959 ESTABLISHED tcp6 0 0 :::22 :::* LISTEN chunli@ubuntu:~/linux_c/network$
客户端最小模型: chunli@ubuntu:~/linux_c/network$ cat client.c #include <stdio.h> #include <string.h> #include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #define SERVER_PORT 8000 int main(void) { struct sockaddr_in serveraddr; int clientfd; char ipstr[] = "11.11.11.3 "; //服务器IP //1创建socket clientfd = socket(AF_INET,SOCK_STREAM,0); //TCP //2初始化服务器地址 bzero(&serveraddr,sizeof(serveraddr)); serveraddr.sin_family =AF_INET; inet_pton(AF_INET,ipstr,&serveraddr.sin_addr.s_addr); serveraddr.sin_port = htons(SERVER_PORT); //3连接服务器 connect(clientfd,(const struct sockaddr *)&serveraddr,sizeof(serveraddr)); //4 请求服务器处理数据 //5 关闭socket close(clientfd); return 0; } 运行4 次 chunli@ubuntu:~/linux_c/network$ gcc -o client -Wall client.c && ./client chunli@ubuntu:~/linux_c/network$ gcc -o client -Wall client.c && ./client chunli@ubuntu:~/linux_c/network$ gcc -o client -Wall client.c && ./client chunli@ubuntu:~/linux_c/network$ gcc -o client -Wall client.c && ./client chunli@ubuntu:~/linux_c/network$ 服务器端窗口输出: chunli@ubuntu:~/linux_c/network$ gcc -o server server.c && ./server client ip 127.0.0.1 ,port:57470 client ip 127.0.0.1 ,port:57472 client ip 127.0.0.1 ,port:57474 client ip 127.0.0.1 ,port:57476
服务端为客户端转换字符大小写 模型
chunli@ubuntu:~/linux_c/network$ cat server.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <netinet/in.h> #include <ctype.h> #include <unistd.h> #include <arpa/inet.h> int main(void) { struct sockaddr_in serveraddr; struct sockaddr_in clientaddr; int socketfd; int clientfd; int addrlen; int port; char ipstr[128]; char buf[4096]; //字符缓冲 int len = 0; //1.socket socketfd = socket(AF_INET,SOCK_STREAM,0); //建立TCP //2.bind bzero(&serveraddr,sizeof(serveraddr)); serveraddr.sin_family = AF_INET; //地址族协议IPV4 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址 serveraddr.sin_port = htons(8000); //端口 bind(socketfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); //3.listen listen(socketfd,128); while(1) { //4.appept addrlen = sizeof(clientaddr); clientfd = accept(socketfd,(struct sockaddr*)&clientaddr,(socklen_t*)&addrlen);//发返回客户端socket //输出客户端Ip地址 和端口号 inet_ntop(AF_INET,&clientaddr.sin_addr.s_addr,ipstr,sizeof(ipstr));//ip数字转字符 port = ntohs(clientaddr.sin_port); //大端转小端 printf("client ip %s ,port:%d \n",ipstr,port); //处理客户请求 len = read(clientfd,buf,sizeof(buf)); int i = 0; while(i < len) { buf[i] = toupper(buf[i]); i++; } write(clientfd,buf,len); //5再见 close(clientfd); } close(socketfd); return 0; } 编译执行: chunli@ubuntu:~/linux_c/network$ gcc -Wall -o server server.c && ./server
chunli@ubuntu:~/linux_c/network$ cat client.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #define SERVER_PORT 8000 int main(int argc,char **argv) { if(argc < 2) { printf("to few argc \n"); exit(1); } struct sockaddr_in serveraddr; int clientfd; char buf[4096]; char ipstr[] = "11.11.11.3 "; //服务器IP //1创建socket clientfd = socket(AF_INET,SOCK_STREAM,0); //TCP //2初始化服务器地址 bzero(&serveraddr,sizeof(serveraddr)); serveraddr.sin_family =AF_INET; inet_pton(AF_INET,ipstr,&serveraddr.sin_addr.s_addr); serveraddr.sin_port = htons(SERVER_PORT); //3连接服务器 connect(clientfd,(const struct sockaddr *)&serveraddr,sizeof(serveraddr)); //4 请求服务器处理数据 write(clientfd,argv[1],strlen(argv[1])); read(clientfd,buf,sizeof(buf)); printf("%s\n",buf); //5 关闭socket close(clientfd); return 0; } chunli@ubuntu:~/linux_c/network$ gcc -o client -Wall client.c && ./client hahahh HAHAHH chunli@ubuntu:~/linux_c/network$ gcc -o client -Wall client.c && ./client Hello_world! HELLO_WORLD! chunli@ubuntu:~/linux_c/network$ 服务端出现的信息: chunli@ubuntu:~/linux_c/network$ gcc -Wall -o server server.c && ./server client ip 127.0.0.1 ,port:57504 client ip 127.0.0.1 ,port:57506