本文谢绝转载原文来自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层。这一层为用户的应用程序(例如电子邮件、文件传输和终端仿真)提供网络服务。

wKiom1e2X-PQQTSpAACgIHJnj-k778.png


 TCP/IP四层模型

一般开发程序员讨论最多的是TCP/IP模型

wKioL1e2YDCw5ltwAABkgxNxic0644.png




以太网封装格式


wKioL1e2ZUjCy39xAADIPMJ1jGE406.jpg



ARP数据报格式

wKiom1e2ZdLAKjKlAAEHwVL4QCg751.png



IP数据报格式

wKioL1e2ZlHAhGrSAAD1nGtGiUU488.png


TCP数据报格式

wKiom1e2ZlzDo4fTAADU3ckTcNA001.png

UDP数据报格式

wKioL1e2ZmrDddqBAAB0qvV3SHI710.png


TCP状态转换图

wKiom1e2Znewl9noAAIqX7vKsg4368.png


TCP连接与断开

wKioL1e2ZqbS6gqRAAFaRZpc-e0973.png

数据进入协议栈时封装过程

wKiom1e2ZQGgH6TeAAEjsuraaz4959.png

socketAPI

wKiom1e2ZoTzXeyfAAIGShHZTTI390.png

大端小端


"大端"和"小端"表示多字节值的哪一端存储在该值的起始地址处;

小端存储在起始地址处,即是小端字节序;

大端存储在起始地址处,即是大端字节序; 

或者说: 

1.小端法(Little-Endian)就是低位字节排放在内存的低地址端(即该值的起始地址),

高位字节排放在内存的高地址端;


2.大端法(Big-Endian)就是高位字节排放在内存的低地址端(即该值的起始地址),

低位字节排放在内存的高地址端; 举个简单的例子,对于整型数据0x12345678,

它在大端法和小端法的系统中,各自的存放方式:


wKiom1e2ZszgtgHSAABQ9zyZXN8061.jpg


查看最大连接数

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