网络编程1

  1 1. 网络基础概念                                                                                             
  2 1.1 协议                                                                        
  3     概念:协议事先约定好,大家共同遵守的一组规则,如交通信号灯.                 
  4     从应用程序的角度看,协议可理解为数据传输和数据解释的规则;                  
  5     可以简单的理解为各个主机之间进行通信所使用的共同语言.                       
  6                                                                                 
  7     假设,A、B双方欲传输文件。规定:                                            
  8     第一次:传输文件名,接收方接收到文件名,应答OK给传输方;                    
  9     第二次:发送文件的尺寸,接收方接收到该数据再次应答一个OK;                  
 10     第三次:传输文件内容。同样,接收方接收数据完成后应答OK表示文件内容接收成功。
 11                                                                                 
 12 1.2 OSI七层模型                                                                 
 13     OSl是Open System lnterconnection的缩写,意为开放式系统互联,国际标准化组织(ISO)制定了OSI模型,
 14     该模型定义了不同计算机互联的标准,是设计和描述计算机网络通信的基本框架      
 15                                                                                 
 16     网络分层OS17层模型:物数网传会表应                                          
 17     物理层:                                                                     
 18         双绞线,光纤(传输介质),将模拟信号转换为数字信号                      
 19     数据链路层:(ARP  RARP)                                                      
 20         [数据校验],定义了网络传输的基本单位"帧".                                
 21     网络层:(IP,、ICMP协议、IGMP协议)                                            
 22         定义网络,两台机器之间传输的路径选择"点到点"的传输(路由器)              
 23     传输层:(TCP UDP)                                                            
 24         传输数据TCP,UDP,"端到端"的传输                                        
 25     会话层:                                                                     
 26         通过传输层建立数据传输的通道.                                           
 27     表示层:                                                                     
 28         编解码,翻译工作。                                                      
 29     应用层:(http ssh email ftp)
 30         为客户提供各种应用服务,email服务,ftp服务,ssh服务                     
 31                                                                                 
 32                                                                                 
 33     TCP四层模型:                                                               
 34         数据链路层:物理层+数据链路程                                           
 35         网络层:网络层                                                          
 36         传输层:传输层                                                          
 37         应用层:会话层,表示层,应用层                                          
 38                                                                                 
 39                                                                                 
 40 1.3 以太网帧格式                                                                
 41     以太网帧格式就是包装在网络接口层(数据链路层)的协议                          
 42                                                                                 
 43     目的地址   源地址   类型    数据        CRC                                 
 44         6        6       2      46~1500      4   (字节单位)                     
 45                                                                                 
 46     类型:                                                                      
 47         0800:IP数据报(46~1500)                                                 
 48         0806:ARP请求/应答(28) + PAD(18)                                        
 49         8035: RARP请求/应答(28) + PAD(18)                                       
 50                                                                                 
 51     以ARP协议为例介绍以太网帧格式:                                             
 52                                                                                 
 53                                                                                                             
 54                                                                                                             
    序号:TCP是安全可靠的,每个数据包都带有序号,当数据包丢失的时候,需要重传,要使用序号进行重传控制数据有序,
 55       丢包重传.                                                                 
 56 确认序号:使用确认序号可以知道对方是否已经收到了,通过确认序号可以知道哪个序号的数据需要重传.
 57     16位窗口大小一滑动窗口(主要进行流量控制)   
 58                                                                                 
 59                                                                                 
 60                                                                                 
 61 2.  socket编程预备知识                                                          
 62                                                                                 
 63     网络字节序:                                                                 
 64         大端和小端的概念                                                        
 65                 大端: 低位地址存放高位数据, 高位地址存放低位数据                
 66                 小端: 低位地址存放低位数据, 高位地址存放高位数据                
 67                                                                                 
 68     大端和小端的使用使用场合???                                                 
 69     大端和小端只是对数据类型长度是两个及以上的,int  short, 对于单字节没限制,在网络中经常需要考虑大端和小
 70     端的是IP和端口.                                                             
 71                                                                                 
 72                                                                                 
 73                                                                                 
 74 3. 一些函数                                                                     
 75     网络传输用的是大端法, 如果机器用的是小端法, 则需要进行大小端的转换.         
 76     下面4个函数就是进行大小端转换的函数:                                        
 77         #include <arpa/inet.h>                                                  
 78                                                                                 
 79         uint32_t htonl(uint32_t hostlong);                                      
 80         uint16_t htons(uint16_t hostshort);                                     
 81         uint32_t ntohl(uint32_t netlong);                                       
 82         uint16_t ntohs(uint16_t netshort);                                      
 83         函数名的h表示主机host, n表示网络network, s表示short, l表示long          
 84         上述的几个函数, 如果本来不需要转换函数内部就不会做转换.                 
 85                                                                                 
 86     IP地址转换函数:
 87     p->表示点分十进制的字符串形式                                               
 88     to->89     n->表示network网络                                                          
 90                                                                                 
 91     int inet_pton(int af, const char *src, void *dst);                          
 92         函数说明: 将字符串形式的点分十进制IP转换为大端模式的网络IP(整形4字节数) 
 93         参数说明:                                                               
 94             af: AF_INET                                                         
 95             src: 字符串形式的点分十进制的IP地址                                 
 96             dst: 存放转换后的变量的地址                                         
 97         例如: inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);           
 98                                                                                 
 99         手工也可以计算:192.168.232.145, 先将4个正数分别转换为16进制数,       
100         192--->0xC0  168--->0xA8   232--->0xE8   145--->0x91                    
101         最后按照大端字节序存放: 0x91E8A8C0, 这个就是4字节的整形值.              
102                                                                                 
103                                                                                 
104     const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);  
105         函数说明: 网络IP转换为字符串形式的点分十进制的IP                        
106     参数说明:                                                                   
107         af: AF_INET                                                             
108         src: 网络的整形的IP地址                                                 
109         dst: 转换后的IP地址,一般为字符串数组                                    
110         size: dst的长度                                                         
111     返回值:                                                                     
112         成功--返回指向dst的指针                                                 
113         失败--返回NULL, 并设置errno                                             
114                                                                                 
115     例如: IP地址为010aa8c0, 转换为点分十进制的格式:
116     01---->1    0a---->10   a8---->168   c0---->192                             
117     由于从网络中的IP地址是高端模式, 所以转换为点分十进制后应该为:   192.168.10.1
118                                                                                 
119                                                                                 
120                                                                                 
121     struct sockaddr ==> struct sockaddr_in                                      
122                                                                                 
123     struct sockaddr {                                                           
124         sa_family_t sa_family;                                                  
125         char        sa_data[14];                                                
126     }                                                                           
127                                                                                 
128     struct sockaddr_in {                                                        
129         sa_family_t    sin_family; /* address family: AF_INET */                
130         in_port_t      sin_port;   /* port in network byte order */             
131         struct in_addr sin_addr;   /* internet address */                       
132     };                                                                          
133                                                                                 
134     /* Internet address. */                                                     
135     struct in_addr {                                                            
136         uint32_t  s_addr;           /* address in network byte order */         
137     };   //网络字节序IP--大端模式                                               
138                                                                                 
139                                                                                 
140     通过man 7 ip可以查看相关说明                                                
141                                                                                 
142                                                                                 
143 4. socket编程主要的API函数介绍 
144                                                                                 
145     int socket(int domain, int type, int protocol);                             
146         函数描述: 创建socket                                                    
147         参数说明:                                                               
148             domain: 协议版本                                                    
149                 AF_INET:  IPV4                                                  
150                 AF_INET6: IPV6                                                  
151                 AF_UNIX AF_LOCAL本地套接字使用                                  
152             type:协议类型                                                       
153                 SOCK_STREAM 流式, 默认使用的协议是TCP协议                       
154                 SOCK_DGRAM  报式, 默认使用的是UDP协议                           
155             protocal:                                                           
156                 一般填0, 表示使用对应类型的默认协议.                            
157         返回值:                                                                 
158             成功: 返回一个大于0的文件描述符                                     
159             失败: 返回-1, 并设置errno                                           
160                                                                                 
161     当调用socket函数以后, 返回一个文件描述符, 内核会提供与该文件描述符相对应的读和写缓冲区,                 
    同时还有两个队列, 分别是请求连接队列和已连接队列.
162                                                                                 
163                                                                                 
164     int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);       
165     函数描述: 将socket文件描述符和IP,PORT绑定                                   
166     参数说明:                                                                   
167         socket: 调用socket函数返回的文件描述符                                  
168         addr: 本地服务器的IP地址和PORT,                                         
169             struct sockaddr_in serv;                                            
170             serv.sin_family = AF_INET;                                          
171             serv.sin_port = htons(8888);
172             //serv.sin_addr.s_addr = htonl(INADDR_ANY);                         
173             //INADDR_ANY: 表示使用本机任意有效的可用IP                          
174                                                                                 
175             inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);             
176         addrlen: addr变量的占用的内存大小                                       
177     返回值:                                                                     
178         成功: 返回0                                                             
179         失败: 返回-1, 并设置errno                                               
180                                                                                 
181                                                                                 
182     int listen(int sockfd, int backlog);                                        
183     函数描述: 将套接字由主动态变为被动态                                        
184     参数说明:                                                                   
185         sockfd: 调用socket函数返回的文件描述符                                  
186         backlog: 同时请求连接的最大个数(还未建立连接)                           
187     返回值:                                                                     
188         成功: 返回0                                                             
189         失败: 返回-1, 并设置errno                                               
190                                                                                 
191     int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);          
192     函数说明:获得一个连接, 若当前没有连接则会阻塞等待.                          
193     函数参数:                                                                   
194         sockfd: 调用socket函数返回的文件描述符                                  
195         addr: 传出参数, 保存客户端的地址信息                                    
196         addrlen: 传入传出参数,  addr变量所占内存空间大小                        
197     返回值:                                                                     
198         成功: 返回一个新的文件描述符,用于和客户端通信                           
199         失败: 返回-1, 并设置errno值. 
200                                                                                 
201     accept函数是一个阻塞函数, 若没有新的连接请求, 则一直阻塞.                   
202         从已连接队列中获取一个新的连接, 并获得一个新的文件描述符, 该文件描述符用于和客户端通信.             
    (内核会负责将请求队列中的连接拿到已连接队列中)
203                                                                                 
204     int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);    
205     函数说明: 连接服务器                                                        
206     函数参数:                                                                   
207         sockfd: 调用socket函数返回的文件描述符                                  
208         addr:   服务端的地址信息                                                
209         addrlen: addr变量的内存大小                                             
210     返回值:                                                                     
211         成功: 返回0                                                             
212         失败: 返回-1, 并设置errno值                                             
213                                                                                 
214                                                                                 
215     //读写操作                                                                  
216     接下来就可以使用write和read函数进行读写操作了.                              
217     除了使用read/write函数以外, 还可以使用recv和send函数                        
218                                                                                 
219     读取数据和发送数据:                                                         
220     ssize_t read(int fd, void *buf, size_t count);                              
221     ssize_t write(int fd, const void *buf, size_t count);                       
222                                                                                 
223     ssize_t recv(int sockfd, void *buf, size_t len, int flags);                 
224     ssize_t send(int sockfd, const void *buf, size_t len, int flags);           
225     对应recv和send这两个函数flags直接填0就可以了.                               
226                                                                                 
227     注意: 如果写缓冲区已满, write也会阻塞, read读操作的时候, 若读缓冲区没有数据会引起阻塞. 

 228                                                                                 
229                                                                                 
230     服务端开发流程:                                                            
231     1.创建socket,返回一个文件描述符lfd---socket()                            
232         --该文件描述符用于监听客户端连接                                        
233     2.将lfd和IP  PORT进行绑定----bind()                                       
234     3.将lfd由主动变为被动监听----listen()                                     
235     4.接受一个新的连接,得到一个文件描述符cfd----accept()                     
236         ---该文件描述符是用于和客户端进行通信的                                 
237     5.while1238     {                                                                           
239         接收数据---read或者recv                                                 
240         发送数据---write或者send                                                
241     }                                                                           
242     6.关闭文件描述符----close(1fd)close(cfd);

代码client.c

  1 //这里是客户端的代码                                                                                        
  2 //功能:主要是先从STDIN_FILENO里面去读取数据,然后将数据发送给服务端;          
  3 //      服务端会先去读取信息,将读取到的信息进行全部转换成大写,然后再发回送给客户端
  4                                                                                 
  5                                                                                 
  6 #include <stdio.h>                                                              
  7 #include <stdlib.h>                                                             
  8 #include <unistd.h>                                                             
  9 #include <sys/socket.h>                                                         
 10 #include <sys/types.h>                                                          
 11 #include <string.h>                                                             
 12 #include <arpa/inet.h>                                                          
 13                                                                                 
 14 //客户端的代码                                                                  
 15                                                                                 
 16 int main ()                                                                     
 17 {                                                                               
 18     int ret;                                                                    
 19                                                                                 
 20     //创建直接通信文件描述符                                                    
 21     int sockfd = socket(AF_INET, SOCK_STREAM, 0);                               
 22     if(sockfd < 0)                                                              
 23     {                                                                           
 24         perror("sockfd error\n");                                               
 25         return -1;                                                              
 26     }                                                                           
 27                                                                                 
 28                                                                                 
 29     //连接服务器  
  30     struct sockaddr_in server_add; //服务端的信息                               
 31                                                                                 
 32     server_add.sin_family = AF_INET;                                            
 33     server_add.sin_port   = htons(8080);                                        
 34     inet_pton(AF_INET, "127.0.0.1", &server_add.sin_addr.s_addr);               
 35                                                                                 
 36     ret = connect(sockfd, (struct sockaddr *) &(server_add), sizeof(server_add));
 37     if(ret < 0)                                                                 
 38     {                                                                           
 39         perror("connect error\n");                                              
 40         return -1;                                                              
 41     }                                                                           
 42                                                                                 
 43     //发送和读消息                                                              
 44     int  n = 0;                                                                 
 45     char buf[1024];                                                             
 46                                                                                 
 47     while(1)                                                                    
 48     {                                                                           
 49         //读取标准输入数据                                                      
 50         memset(buf, 0, sizeof(buf));                                            
 51         n = read(STDIN_FILENO, buf, sizeof(buf));                               
 52                                                                                 
 53         //发送数据                                                              
 54         write(sockfd, buf, n);                                                  
 55                                                                                 
 56         //读服务端发来的数据                                                    
 57         memset(buf, 0, sizeof(buf));  
  58         n = read(sockfd, buf, sizeof(buf));                                     
 59         if(n <= 0)                                                              
 60         {                                                                       
 61             printf("read error | server exit,n = [%d]\n",n);                    
 62             break;                                                              
 63         }                                                                       
 64                                                                                 
 65         printf("n == [%d], buf == [%s]\n",n ,buf);                              
 66     }                                                                           
 67                                                                                 
 68     close(sockfd);                                                              
 69                                                                                 
 70     return 0;                                                                   
 71 }                                                                               
 72                                                                                 
 73    

代码server.c

  1 //这里是客户端的代码                                                                                        
  2 //功能:主要是先从STDIN_FILENO里面去读取数据,然后将数据发送给服务端;                                      
  3 //      服务端会先去读取信息,将读取到的信息进行全部转换成大写,然后再发回送给客户端
  4                                                                                 
  5 #include <stdio.h>                                                              
  6 #include <stdlib.h>                                                             
  7 #include <unistd.h>                                                             
  8 #include <sys/socket.h>                                                         
  9 #include <sys/types.h>                                                          
 10 #include <string.h>                                                             
 11 #include <arpa/inet.h>                                                          
 12                                                                                 
 13 int main ()                                                                     
 14 {                                                                               
 15     int ret;                                                                    
 16                                                                                 
 17     //创建监听文件描述符                                                        
 18     int sockfd = socket(AF_INET, SOCK_STREAM, 0);                               
 19     if(sockfd < 0)                                                              
 20     {                                                                           
 21         perror("sockfd error\n");                                               
 22         return -1;                                                              
 23     }                                                                           
 24                                                                                 
 25     //绑定ip 以及 端口port                                                      
 26     struct sockaddr_in server_add; //服务器端的结构体,包含服务器端的ip和port   
 27     bzero(&server_add, sizeof(server_add));                                     
 28                                                                                 
 29     server_add.sin_family = AF_INET; 
 30     server_add.sin_port   = htons(8080);                                        
 31     inet_pton(AF_INET, "127.0.0.1", &server_add.sin_addr.s_addr);               
 32                                                                                 
 33     ret = bind(sockfd, (struct sockaddr *)&server_add, sizeof(server_add));     
 34     if(ret < 0)                                                                 
 35     {                                                                           
 36         perror("bind error\n");                                                 
 37         return -1;                                                              
 38     }                                                                           
 39                                                                                 
 40     //listen由主动变成被动态                                                    
 41     ret = listen(sockfd, 10);                                                   
 42     if(ret < 0)                                                                 
 43     {                                                                           
 44         perror("listen error\n");                                               
 45         return -1;                                                              
 46     }                                                                           
 47                                                                                 
 48                                                                                 
 49     //接受一个新的连接,得到一个可通信的文件描述符                              
 50     struct sockaddr_in client_addr; //用来接收客户端的信息的                    
 51     int len = sizeof(client_addr);                                              
 52     int newsockfd = accept(sockfd,(struct sockaddr*) &(client_addr), &len);     
 53     if(newsockfd < 0)                                                           
 54     {                                                                           
 55         perror("accept error\n");                                               
 56         return -1;                                                              
 57     }    
 58                                                                                 
 59     printf("sockfd = [%d], newsockfd = [%d]\n",sockfd, newsockfd);              
 60                                                                                 
 61     //打印出接收的客户端的信息                                                  
 62     char client_ip[16];                                                         
 63     printf("client: ip = %s, port = %d\n", inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, client_ip,      
    sizeof(client_ip)), ntohs(client_addr.sin_port));
 64                                                                                 
 65     //接收消息                                                                  
 66     int i, n;                                                                   
 67     char buf[1024];                                                             
 68     while(1)                                                                    
 69     {                                                                           
 70         memset(buf, 0, sizeof(buf));                                            
 71                                                                                 
 72         //服务端先去接收数据                                                    
 73         n = recv(newsockfd, buf, sizeof(buf),0);                                
 74         if(n <= 0)                                                              
 75         {                                                                       
 76             printf("recv error | client exit, n = [%d]\n",n);                   
 77             break;                                                              
 78         }                                                                       
 79                                                                                 
 80         //打印接收到的数据字节数和数据内容printf("server: n = [%d], buf = [%s]\n",n, recv_buf);
 81         printf("server: n = [%d], buf = [%s]\n",n, buf);                        
 82         for(i=0; i<n; i++)                                                      
 83         {                                                                       
 84             buf[i] = toupper(buf[i]);//将小写转换成大写                         
 85         }   
 86                                                                                 
 87         //发送数据出去到客户端                                                  
 88         send(newsockfd, buf, n, 0);                                             
 89     }                                                                           
 90                                                                                 
 91     close(sockfd);                                                              
 92     close(newsockfd);                                                           
 93                                                                                 
 94 }                                                                               
 95                                                                                 
 96    
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值