linux c 网络编程

linux c 网络编程
转载 2017年09月09日 23:58:46
OSI七层网络模型由下至上为1至7层,分别为:
物理层(Physical layer),数据链路层(Data link layer),网络层(Network layer),传输层(Transport layer),会话层(Session layer),表示层(Presentation layer),应用层(Application layer)。
1.1 应用层,很简单,就是应用程序。这一层负责确定通信对象,并确保由足够的资源用于通信,这些当然都是想要通信的应用程序干的事情。 
1.2 表示层,负责数据的编码、转化,确保应用层的正常工作。这一层,是将我们看到的界面与二进制间互相转化的地方,就是我们的语言与机器语言间的转化。数据的压缩、解压,加密、解密都发生在这一层。这一层根据不同的应用目的将数据处理为不同的格式,表现出来就是我们看到的各种各样的文件扩展名。 
1.3 会话层,负责建立、维护、控制会话,区分不同的会话,以及提供单工(Simplex)、半双工(Half duplex)、全双工(Full duplex)三种通信模式的服务。我们平时所知的NFS,RPC,X Windows等都工作在这一层。 
1.4 传输层,负责分割、组合数据,实现端到端的逻辑连接。数据在上三层是整体的,到了这一层开始被分割,这一层分割后的数据被称为段(Segment)。三次握手(Three-way handshake),面向连接(Connection-Oriented)或非面向连接(Connectionless-Oriented)的服务,流控(Flow control)等都发生在这一层。 
1.5 网络层,负责管理网络地址,定位设备,决定路由。我们所熟知的IP地址和路由器就是工作在这一层。上层的数据段在这一层被分割,封装后叫做包(Packet),包有两种,一种叫做用户数据包(Data packets),是上层传下来的用户数据;另一种叫路由更新包(Route update packets),是直接由路由器发出来的,用来和其他路由器进行路由信息的交换。 
1.6 数据链路层,负责准备物理传输,CRC校验,错误通知,网络拓扑,流控等。我们所熟知的MAC地址和交换机都工作在这一层。上层传下来的包在这一层被分割封装后叫做帧(Frame)。 
1.7 物理层,就是实实在在的物理链路,负责将数据以比特流的方式发送、接收,就不多说了。 
 
3.2,TCP握手
3.2.1 三次握手建立连接
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
1,客户端向服务器发送一个SYN J
2,服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+1
3,客户端再想服务器发一个确认ACK K+1
 
从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。
三次握手的目的是建立双向的连接,第一次握手是客户端向服务器端发出请求 
第二次握手是服务器端告诉客户端,第一次握手是成功的,即可以从客户端发送到客户端, 
第三次握手是客户端告诉服务器端,第二次握手是成功的,即可以从客户端到服务器端 
这样就保证了客户端和服务器端的双向通信,
3.2.2 四次握手释放连接
 
1,某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;
2,另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;
3,一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;
4,接收到这个FIN的源发送端TCP对它进行确认。
3.3,socket编程
先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
3.3.1 AF_INET TCP传输最简单版本
 
tcp_client.c
  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <errno.h>  
  6. #include <sys/types.h>  
  7. #include <sys/socket.h>  
  8. #include <netinet/in.h>  
  9.   
  10. #define PORT 6666  
  11. #define BUFF_SIZE 1024  
  12. #define MAXLEN 4096  
  13.   
  14. main(int argc, char** argv)  
  15. {  
  16.     if(argc!=2){  
  17.         printf("usage: ./client <ipaddress>\n");  
  18.         exit(0);  
  19.     }  
  20.       
  21.     char sendline[4096];  
  22.       
  23.     //socket()建立socket  
  24.     int sockfd = socket(AF_INET,SOCK_STREAM,0);  
  25.   
  26.     //要连接的服务器地址  
  27.     struct sockaddr_in sliaddr;  
  28.     sliaddr.sin_family = AF_INET;  
  29.     sliaddr.sin_port = htons(PORT);  
  30.     inet_pton(AF_INET, argv[1], &sliaddr.sin_addr);  
  31.   
  32.     //connect()发送请求(ip=argv[1],protocal=TCP,port=6666)  
  33.     connect(sockfd, (struct sockaddr*)&sliaddr, sizeof(sliaddr));  
  34.   
  35.     //recv sth  
  36.     recv_len = recv(sockfd, buff, sizeof(buff), 0);  
  37.     buff[recv_len] = '\0';  
  38.     printf(" %s ", buff);  
  39.    
  40.     //interactive  
  41.     while (1)  
  42.     {  
  43.         printf("Enter string to send: ");  
  44.         scanf("%s", buff);  
  45.         if (!strcmp(buff, "quit"))  
  46.             break;  
  47.            
  48.         send_len = send(sockfd, buff, strlen(buff), 0);  
  49.         recv_len = recv(sockfd, buff, BUFF_SIZE, 0);  
  50.         buff[recv_len] = '\0';  
  51.         printf("    received: %s \n", buff);  
  52.     }  
  53.   
  54.     //close()关闭连接  
  55.     close(sockfd);  
  56. }  
 
tcp_server.c
  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <errno.h>  
  6. #include <sys/types.h>  
  7. #include <sys/socket.h>  
  8. #include <netinet/in.h>  
  9.   
  10. #define PORT 6666  
  11. #define WAIT_QUEUE_LEN 5  
  12. #define BUFF_SIZE 1024  
  13. #define WELCOME "Welcome to my server ^_^!\n"  
  14.   
  15. main()  
  16. {  
  17.     int connfd;  
  18.     char buff[MAXLEN];  
  19.     int len;  
  20.   
  21.     //socket() 建立socket,其中SOCK_STREAM表示tcp连接  
  22.     int sockfd = socket(AF_INET,SOCK_STREAM,0);  
  23.       
  24.     struct sockaddr_in servaddr;  
  25.     servaddr.sin_family = AF_INET;  
  26.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  27.     servaddr.sin_port = htons(PORT);  
  28.       
  29.     //bind()绑定一个socket(ip=all,protocal=TCP,port=6666)  
  30.     bind(sockfd,(struct sockaddr *) &servaddr, sizeof(servaddr));  
  31.   
  32.     //listen()监听  
  33.     listen(sockfd, WAIT_QUEUE_LEN);  
  34.   
  35.     //accept() & close()  
  36.     printf("======waiting for client's request======\n");  
  37.     while(1){  
  38.         c_addrlen = sizeof(struct sockaddr_in);  
  39.         connfd = accept(serverfd, (struct sockaddr *)&caddr, &c_addrlen);  
  40.         printf("client: ip=%s,port=%s\n", cliaddr.sin_addr.s_addr,cliaddr.sin_port);  
  41.           
  42.         //send a welcome  
  43.         send(connfd, WELCOME, strlen(WELCOME), 0);  
  44.        
  45.         //阻塞模式下recv==0表示客户端已断开连接  
  46.         while ((len = recv(connfd, buff, BUFF_SIZE, 0)) > 0)  
  47.         {  
  48.             buff[len] = '\0';  
  49.             printf("recv msg is : %s \n", buff);  
  50.             send(connfd, buff, len, 0);  
  51.         }  
  52.           
  53.         close(connfd);  
  54.     }  
  55.   
  56.     //close()关闭连接  
  57.     close(sockfd);  
  58. }  
阻塞与非阻塞recv返回值没有区分,都是
<0 出错
=0 连接关闭
>0 接收到数据大小,
makefile
[plain] view plain copy
  1. .PHONY : main  
  2. main : server client  
  3. server : server.o  
  4.         gcc -g -o server server.o   
  5. client : client.o  
  6.         gcc -g -o client client.o   
  7. server.o : server.c  
  8.         gcc -g -c server.c  
  9. client.o : client.c  
  10.         gcc -g -c client.c  
  11. clean :   
  12.         rm -rf *.o  
  13. ser :  
  14.         ./server  
  15. cli :  
  16.         ./client  
3.3.2 加入返回值检查和IP地址
tcp_client.c
  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <errno.h>  
  6. #include <sys/types.h>  
  7. #include <sys/socket.h>  
  8. #include <netinet/in.h>  
  9.   
  10. #define MAXLEN 4096  
  11.   
  12. main(int argc, char** argv)  
  13. {  
  14.     if(argc!=2){  
  15.         printf("usage: ./client <ipaddress>\n");  
  16.         exit(0);  
  17.     }  
  18.       
  19.     char sendline[4096];  
  20.       
  21.     //socket()建立socket  
  22.     int sockfd;  
  23.     if((sockfd=socket(AF_INET,SOCK_STREAM,0)) ==-1){  
  24.         printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);  
  25.     }  
  26.   
  27.     struct sockaddr_in cliaddr;  
  28.     cliaddr.sin_family = AF_INET;  
  29.     cliaddr.sin_port = htons(6666);  
  30.     if(inet_pton(AF_INET, argv[1], &cliaddr.sin_addr)==-1){  
  31.         printf("inet_pton error for %s\n",argv[1]);  
  32.         exit(0);  
  33.     }  
  34.   
  35.     //connect()发送请求(ip=argv[1],protocal=TCP,port=6666)  
  36.     if(connect(sockfd, (struct sockaddr*)&cliaddr, sizeof(cliaddr))==-1){  
  37.         printf("connect error: %s(errno: %d)\n",strerror(errno),errno);  
  38.         exit(0);  
  39.     }  
  40.   
  41.     printf("send msg to server: \n");  
  42.     fgets(sendline, 4096, stdin);  
  43.   
  44.     //send()发送数据  
  45.     if(send(sockfd, sendline, strlen(sendline), 0)==-1){  
  46.         printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);  
  47.         exit(0);  
  48.     }  
  49.   
  50.     //close()关闭连接  
  51.     close(sockfd);  
  52. }  
 
tcp_server.c
  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <errno.h>  
  6. #include <sys/types.h>  
  7. #include <sys/socket.h>  
  8. #include <netinet/in.h>  
  9.   
  10. #define MAXLEN 4096  
  11.   
  12. main()  
  13. {  
  14.     int connfd;  
  15.     char buff[MAXLEN];  
  16.     int n;  
  17.   
  18.     //socket()建立socket  
  19.     int sockfd;  
  20.     if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){  
  21.         printf("create socket error: %s(errno:%d)\n",strerror(errno),errno);  
  22.         exit(0);  
  23.     }  
  24.       
  25.     struct sockaddr_in servaddr;  
  26.     servaddr.sin_family = AF_INET;  
  27.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  28.     servaddr.sin_port = htons(6666);  
  29.       
  30.     //bind()绑定一个socket(ip=all,protocal=TCP,port=6666)  
  31.     if(bind(sockfd,(struct sockaddr *) &servaddr, sizeof(servaddr))==-1){  
  32.         printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);  
  33.         exit(0);  
  34.     }  
  35.   
  36.     //listen()监听  
  37.     if(listen(sockfd,10)==-1){  
  38.         printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);  
  39.         exit(0);  
  40.     }  
  41.   
  42.     //accept() & close()  
  43.     printf("======waiting for client's request======\n");  
  44.     while(1){  
  45.         if((connfd=accept(sockfd, (struct sockaddr *)NULL,NULL))==-1){  
  46.             printf("accept socket error: %s(errno: %d)",strerror(errno),errno);  
  47.             continue;  
  48.         }  
  49.         struct sockaddr_in serv, guest;  
  50.         char serv_ip[20];  
  51.         char guest_ip[20];  
  52.         int serv_len = sizeof(serv);  
  53.         int guest_len = sizeof(guest);  
  54.         getsockname(connfd, (struct sockaddr *)&serv, &serv_len);  
  55.         getpeername(connfd, (struct sockaddr *)&guest, &guest_len);  
  56.         inet_ntop(AF_INET, &serv.sin_addr, serv_ip, sizeof(serv_ip));  
  57.         inet_ntop(AF_INET, &guest.sin_addr, guest_ip, sizeof(guest_ip));  
  58.         printf("host %s:%d guest %s:%d\n", serv_ip, ntohs(serv.sin_port), guest_ip, ntohs(guest.sin_port));  
  59.         n = recv(connfd, buff, MAXLEN,0);  
  60.         buff[n] = '\0';  
  61.         printf("recv msg from client: %s\n", buff);  
  62.         close(connfd);  
  63.     }  
  64.   
  65.     //close()关闭连接  
  66.     close(sockfd);  
  67. }  
3.3.3 AF_INET UDP传输最简单版本
 
udp_client.c
  1. /** 
  2. *   @file: udpclient.c 
  3. *   @brief: A simple Udp server 
  4. *   @author: ToakMa <mchgloak1120@163.com> 
  5. *   @date:  2014/10/09 
  6. */  
  7.    
  8. #include <stdio.h>  
  9. #include <stdlib.h>  
  10. #include <string.h>  
  11. #include <strings.h>  
  12. #include <sys/types.h>  
  13. #include <sys/socket.h>  
  14. #include <netinet/in.h>  
  15. #include <arpa/inet.h>  
  16.    
  17. #define BUFF_SIZE 1024  
  18. #define PORT     9988  
  19.    
  20. int main(int argc, char *argv[])  
  21. {  
  22.     int sockfd;  
  23.     struct sockaddr_in remote_addr;  
  24.     int len;  
  25.     char buff[BUFF_SIZE];  
  26.    
  27.     //1. create a socket  
  28.     sockfd = socket(AF_INET, SOCK_DGRAM, 0);  
  29.     if (-1 == sockfd)  
  30.     {  
  31.         perror("udp client socket: ");  
  32.         return -1;  
  33.     }  
  34.        
  35.     //2. prepare ip and port  
  36.     memset(&remote_addr, 0, sizeof(remote_addr));  
  37.     remote_addr.sin_family = AF_INET;  
  38.     remote_addr.sin_port   = htons(PORT);  

posted @ 2018-04-19 12:44  LloydDracarys  阅读(265)  评论(0)    收藏  举报