网络编程之套接字(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\n", 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\n", 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\n", 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\n", sum);
66             break;
67         }
68         memset(data, 0, 1024);
69     }
70     close(fd);
71     close(sock_fd);
72     return 0;
73 }

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

  

时间: 2024-11-10 14:43:15

网络编程之套接字(udp)的相关文章

[python] 网络编程之套接字Socket、TCP和UDP通信实例

很早以前研究过C#和C++的网络通信,参考我的文章: C#网络编程之Tcp实现客户端和服务器聊天 C#网络编程之套接字编程基础知识 C#网络编程之使用Socket类Send.Receive方法的同步通讯 Python网络编程也类似.同时最近找工作笔试面试考察Socket套接字.TCP\UDP区别比较多,所以这篇文章主要精简了<Python核心编程(第二版)>第16章内容.内容包括:服务器和客户端架构.套接字Socket.TCP\UDP通信实例和常见笔试考题. 最后希望文章对你有所帮助,如果有不

Linux网络编程——原始套接字实例:简单版网络数据分析器

通过<Linux网络编程--原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 MAC 头部(有线局域网) 注意:CRC.PAD 在组包时可以忽略 链路层数据包的其中一种情况: unsigned char msg[1024] = { //--------------组MAC--------14------ 0xb8, 0x88, 0xe3, 0xe1, 0x10, 0xe6, // dst

Linux网络编程——原始套接字实例:MAC 头部报文分析

通过<Linux网络编程——原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 MAC 头部(有线局域网) 注意:CRC.PAD 在组包时可以忽略 链路层数据包的其中一种情况: 1 unsigned char msg[1024] = { 2 //--------------组MAC--------14------ 3 0xb8, 0x88, 0xe3, 0xe1, 0x10, 0xe6,

TCP/IP网络编程之套接字类型与协议设置

套接字与协议 如果相隔很远的两人要进行通话,必须先决定对话方式.如果一方使用电话,另一方也必须使用电话,而不是书信.可以说,电话就是两人对话的协议.协议是对话中使用的通信规则,扩展到计算机领域可整理为"计算机间对话必备通信规则" 在TCP/IP网络编程之网络编程和套接字这一章中,我们已经介绍了如何创建套接字,但为了完全理解该函数,此处将继续展开讨论 #include <sys/socket.h> int socket(int domain, int type, int pr

Python网络编程—socket套接字编程(UDP)

套接字介绍 1.套接字 : 实现网络编程进行数据传输的一种技术手段 2.Python实现套接字编程:import socket 3.套接字分类 流式套接字(SOCK_STREAM): 以字节流方式传输数据,实现tcp网络传输方案.(面向连接--tcp协议--可靠的--流式套接字) 数据报套接字(SOCK_DGRAM):以数据报形式传输数据,实现udp网络传输方案.(无连接--udp协议--不可靠--数据报套接字) UDP套接字编程 服务端流程 1.创建数据报套接字 sockfd = socket

网络编程--Socket(套接字)

网络编程 网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯.网络编程中 有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后 如何可靠高效的进行数据传输.在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的 路由,由IP地址可以唯一地确定Internet上的一台主机.而TCP层则提供面向应用的可靠的 或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据 的. 目前较为流行的网络编程模型是客户机/服务器(C/S)结构

《网络编程》套接字编程简介

本节介绍的套接字是可以实现不同计算机之间的远程进程间通信.套接口是网络进程的 ID,在网络中每一个节点都有一个网络地址,也就是 IP 地址,两个进程间通信时,首先要确定各自所在网络节点的网络地址.但是,网络地址只要确定进程所在的计算机,由于一台计算机上同时可能有多个网络进程,所以仅凭网络地址还不能确定是网络中的哪一个进程,因此套接口中还需要其他信息,也就是端口.在一台计算机中,一个端口号只能分配给一个进程,所以,进程和端口之间是一一对应的关系.因此,使用端口号和网络地址的组合就能唯一地确定整个网

网络编程之套接字socket

目录 socket套接字 引子 为何学习socket一定要先学习互联网协议 socket是什么 套接字类型 基于文件类型的套接字家族 基于网络类型的套接字家族 套接字工作流程 基于TCP的套接字 简单通信 加上链接循环与通信循环 基于UDP的套接字 UDP的套接字下的简单通信 UDP协议支持并发 粘包现象 什么是粘包 两种情况下会发生粘包 解决粘包问题的处理方法 简单方法(不推荐使用) 牛逼方法(利用struct模块打包报头) socketserver模块(实现并发) socketserver模

Linux 网络编程——原始套接字实例:发送 UDP 数据包

以太网报文格式: 详细的说明,请看<MAC 头部报文分析>. IP 报文格式: 详细的说明,请看<IP 数据报格式详解>. UDP 报文格式: 详细的说明,请看<UDP 数据报格式详解>. 校验和函数: /******************************************************* 功能: 校验和函数 参数: buf: 需要校验数据的首地址 nword: 需要校验数据长度的一半 返回值: 校验和 ********************