zoukankan      html  css  js  c++  java
  • 网络编程之套接字(udp)

       Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一 般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。

      socket()函数原型:

      int socket(int domain, int type, int protocol);

      参数说明: 
      domain:协议域,又称协议族(family)。常用的协议族有AF_INET、 AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域  Socket)、AF_ROUTE等。协议族决定了socket的地址类型,在通信 中必须采用对应的地址,如AF_INET决定了要用ipv4地(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地 址。
      type:指定Socket类型。常用的sinocket类型有SOCK_STREAM、 SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、    SOCK_SEQPACKET等。流式Socket(SOCK_STREAM)是一种 面向连接的Socket,针对于面向连接的TCP服务应用。数  据报式Socket(SOCK_DGRAM)是一种无连接的Socket,对应于无连接的UDP服务应用。  
      protocol:指定协议。常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
      注意:1.type和protocol不可以随意组合,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当第三个参数为0时,会自动选择第二个参数类型对应的默认协议。
      这次的学习任务主要是会使用UDP, TCP 进行通信;练习函数htonl(),htons(),inet_addr(),inet_hton(). 的使用,为了更深入的了解,可以自己编写代码实现;
      下面代码是实现简单的UDP间的通信
      udp发送方:
      
     1 #include <stdio.h>
     2 #include <sys/socket.h>
     3 #include <netinet/in.h>
     4 
     5 int main()
     6 {
     7     int sockfd = 0;
     8     int ret = 0;
     9     unsigned char *data = "hao are you";
    10     
    11     /*创建套接口*/
    12     sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    13     if(sockfd < 0) {
    14         perror("socket");
    15         return 1;
    16     }
    17 
    18     /*接收方信息*/
    19     struct sockaddr_in mm;
    20     mm.sin_family = PF_INET;
    21     mm.sin_port = htons(2001);
    22     mm.sin_addr.s_addr = htonl(0xc0a8010a);
    23 
    24     /*发送消息*/
    25     ret = sendto(sockfd, data, 11, 0, (struct sockaddr *)&mm, sizeof(struct sockaddr_in));
    26     if(ret < 0) {
    27         perror("sendto");
    28         return 1;        
    29     }
    30     close(sockfd);    //关闭套接口
    31 }

      UDP接收方:

      

     1 #include <stdio.h>
     2 #include <sys/socket.h>
     3 #include <netinet/in.h>
     4 
     5 int main()
     6 {
     7     int fd = 0;
     8     int ret = 0;
     9     /*建立套接口*/    
    10     fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    11     if(fd < 0) {
    12         perror("socket");
    13         return 1;
    14     }
    15     /*接收方信息*/
    16     struct sockaddr_in mm;
    17     struct sockaddr_in gg;
    18     int len = 0;
    19     mm.sin_family = AF_INET;
    20     mm.sin_port = htons(2001);
    21     mm.sin_addr.s_addr = htonl(0xc0a8010a); //192.168.1.10 (ip)
    22 
    23     /*绑定*/
    24     ret = bind(fd, (struct sockaddr *)&mm, 16);    
    25     if(ret == -1) {
    26         perror("bind");
    27         return 1;
    28     }
    29     /*接收发送来的消息*/    
    30     unsigned char data[1024] = {0};    
    31     ret = recvfrom(fd, data, 1024, 0, (struct sockaddr *)&gg, &len);        
    32     if(ret < 0) {
    33         perror("recvfrom");
    34         return 1;        
    35     }
    36     printf("send said: %s
    ", data);
    37     close(fd);
    38     return 0;
    39         
    40 }

       从上面代码可以看出udp传输是不可靠传输,发送方只管发送,不知道接收端是否接收到,进行套接口编程的第一步就是通过socket()函数创建一个套接口,后面就需要使用函数sendto(),recvfrom()进行发送和接收,要注意的是,接收方需要通过bind()函数对自己的信息进行绑定;

        下面这个程序是使用UDP进行大文件的传输:
        发送方:
        
     1 #include <stdio.h>
     2 #include <sys/socket.h>
     3 #include <netinet/in.h>
     4 #include <fcntl.h>
     5 #include <string.h>
     6 
     7 int main()
     8 {
     9     int sock_fd = 0;
    10     int ret = 0;
    11     int fd = 0;
    12     unsigned char data[1024] = {0};
    13     /*创建套接口*/    
    14     sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    15     if(sock_fd < 0) {
    16         perror("socket");
    17         return 1;
    18     }
    19     /*打开要传输的文件*/
    20     fd = open("yasm-0.8.0.tar.gz", O_RDWR);
    21     if(fd < 0) {
    22         perror("open");
    23         return 1;
    24     }
    25 
    26     /*添加接收方信息*/
    27     struct sockaddr_in mm;
    28     mm.sin_family = AF_INET;
    29     mm.sin_port = htons(2008);
    30     mm.sin_addr.s_addr = inet_addr("192.168.1.10");
    31 
    32     unsigned char *file_name = "yasm-0.8.0.tar.gz";
    33     ret = sendto(sock_fd, file_name, strlen(file_name), 0, (struct sockaddr *)&mm, 16);
    34     if(ret == -1) {
    35         perror("sendto");
    36         return 1;
    37     }
    38     
    39     int sum = 0;
    40     int file_size = 0;
    41     while(1) {
    42         usleep(2);//发送方每次睡2ms(接收方有足够时间接收)
    43         file_size = read(fd, data, 1024);
    44         if(file_size < 0) {
    45             perror("read");
    46             return 1;
    47         }
    48         /*进行文件发送*/
    49         ret = sendto(sock_fd, data, file_size, 0, (struct sockaddr *)&mm, 16);
    50         if(ret == -1) {
    51             perror("sendto");
    52             return 1;
    53         }
    54         printf("file is:%d
    ", file_size);
    55         sum += file_size;
    56         if(file_size < 1024) {
    57             break;
    58         }
    59         memset(data, 0, 1024); //清空缓冲区
    60     }
    61     printf("file is:%d
    ", sum);
    62     close(fd);
    63     close(sock_fd);    
    64     
    65     return 0;
    66 }

      接收方:

     1 #include <stdio.h>
     2 #include <sys/socket.h>
     3 #include <netinet/in.h>
     4 #include <fcntl.h>
     5 
     6 int main()
     7 {
     8     int sock_fd = 0;
     9     int fd = 0;
    10     int ret = 0;
    11     unsigned char file_name[18] = {0};
    12     struct sockaddr_in mm;    
    13     struct sockaddr_in gg;
    14     int len = 0;
    15     int sum = 0;
    16     char data[1024] = {0};
    17     int file_size = 0;
    18 
    19     /*创建套接口*/
    20     sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    21     if(sock_fd < 0) {
    22         perror("socket");
    23         return 1;
    24     }
    25     /*接收方信息*/    
    26     mm.sin_family = AF_INET;
    27     mm.sin_port = htons(2008);
    28     mm.sin_addr.s_addr =htonl(0xc0a8010a);
    29 
    30     /*绑定信息*/
    31     ret = bind(sock_fd, (struct sockaddr *)&mm, 16);
    32     if(ret == -1) {
    33         perror("bind");
    34         return 1;
    35     }
    36 
    37     /*接收文件名*/
    38     ret = recvfrom(sock_fd, file_name, 17, 0, (struct sockaddr *)&gg, &len);
    39     if(ret < 0) {
    40         perror("recvfrom");
    41         return 1;
    42     }
    43     
    44     /*创建一个新文件用来接收*/
    45     fd = open(file_name, O_RDWR | O_CREAT, 0644);
    46     if(fd < 0) {
    47         perror("open");
    48         return 1;
    49     }    
    50     
    51     while(1) {
    52         /*接收*/
    53         file_size = recvfrom(sock_fd, data, 1024, 0, (struct sockaddr *)&gg, &len);            
    54         if(file_size < 0) {
    55             perror("recvfrom");
    56             return 1;
    57         }
    58         ret = write(fd, data, file_size);
    59         if(ret < 0) {
    60             perror("write");
    61             return 1;
    62         }
    63         sum += file_size;//统计文件大小
    64         if(file_size < 1024) {
    65             printf("file_size: %d
    ", sum);
    66             break;
    67         }
    68         memset(data, 0, 1024);                
    69     }
    70     close(fd);
    71     close(sock_fd);
    72     return 0;
    73 }

      传输文件的思想就是通过循环进行传输,在程序中需要注意的是:发送方在发送的时候要延迟一会儿,不然会造成接收端来不及接收,导致数据流失;

      

     
     
  • 相关阅读:
    C#显示接口实现和隐式接口实现
    JAVA8新特性总结一(接口函数默认实现)
    接口(策略设计模式)
    自定义注解
    C# Task的GetAwaiter和ConfigureAwait
    UNIX(编程-进程处理):30---僵死进程、孤儿进程(SIGCLD、SIGHCLD信号处理)
    C# 静态变量会被gc回收么?
    C# 托管资源与非托管资源
    WebSocket与消息推送
    Quartz.NET实现作业调度
  • 原文地址:https://www.cnblogs.com/wenqiang/p/4760117.html
Copyright © 2011-2022 走看看