赞
踩
特点:
1、邮件系统服务模式的抽象
2、每个分组都携带完整的目的地址
3、不能保证分组的先后顺序
4、不进行分组出错的恢复和重传
5、不保证数据传输的可靠性
面向无连接的用户数据报协议,在传输数据前不需要先建立连接;目地主机的运输层收到 UDP 报文后,不需要给出任何确认。
UDP 其它特点
1、相比 TCP 速度稍快些
2、简单的请求/应答应用程序可以使用 UDP
3、对于海量数据传输不应该使用 UDP
4、广播和多播应用必须使用 UDP
UDP 应用
DNS(域名解析)、NFS(网络文件系统)、RTP(流媒体)等
提供不同主机上的进程之间的通信
1、socket 也称“套接字”
2、是一种文件描述符,代表了一个通信管道的一个端点
3、类似对文件的操作一样,可以使用 read、write、close 等函数对 socket 套接字进行网络 数据的收取和发送等操作。
4、得到 socket 套接字(描述符)的方法调用 socket()
头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数:int socket(int domain, int type, int protocol);
功能:创建一个套接字,返回一个文件描述符
参数:
domain:通信域,协议族
AF_UNIX 本地通信
AF_INET ipv4网络协议(常用)
AF_INET6 ipv6网络协议
AF_PACKET 底层接口type:套接字的类型
SOCK_STREAM 流式套接字(TCP)
SOCK_DGRAM 数据报套接字(UDP)本章学习UDP
SOCK_RAW 原始套接字(用于链路层)
protocol:附加协议,如果不需要,则设置为0
返回值:
成功:文件描述符
失败:‐1
特点:
创建套接字时,系统不会分配端口
创建的套接字默认属性是主动的,即主动发起服务的请求;当作为服务器时,往往需要修改为被动的。
- #include <stdio.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <stdlib.h>
-
- int main(int argc, char const *argv[])
- {
- //使用socket函数创建套接字
- //创建一个用于UDP网络编程的套接字
- int sockfd;
- if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == ‐1)
- {
- perror("fail to socket");
- exit(1);
- }
-
- printf("sockfd = %d\n", sockfd);
-
- return 0;
- }

运行结果
sockfd = 3
头文件
#include <sys/types.h>
#include <sys/socket.h>
函数:ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
功能:发送数据
参数:
sockfd:文件描述符,socket的返回值
buf:要发送的数据
len:buf的长度
flags:标志位
0 阻塞 (基本都设置为0)
MSG_DONTWAIT 非阻塞
dest_addr:目的网络信息结构体(需要自己指定要给谁发送)
addrlen:dest_addr的长度
返回值:
成功:发送的字节数
失败:‐1
此函数,重点 :const struct sockaddr *dest_addr 如何构建
通过man手册查询:sockaddr通用结构体
头文件:
#include <netinet/in.h>
函数结构体:
struct sockaddr
{
sa_family_t sa_family; // 2字节
char sa_data[14] //14字节
};
但是,在网络编程中经常使用的结构体sockaddr_in
头文件:
#include <netinet/in.h>
函数结构体:
struct sockaddr_in
{
sa_family_t sin_family; //协议族 2字节
in_port_t sin_port; //端口号 2字节
struct in_addr sin_addr; //ip地址 4字节
char sin_zero[8] //填充,不起什么作用 8字节
};struct in_addr
{
in_addr_t s_addr; //ip地址 4字节
};
在定义源地址和目的地址结构的时候,选用struct sockaddr_in;
例:
struct sockaddr_in my_addr;
当调用编程接口函数,且该函数需要传入地址结构时需要用struct sockaddr进行强制转换
例:
bind(sockfd,(struct sockaddr*)&my_addr,sizeof(my_addr));
设置网络调试助手(在windows下运行的软件)中的属性
注意:ip地址不能随意设置,必须是当前windows的ip地址
- #include<stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include<stdlib.h>
- #include <unistd.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include<string.h>
-
-
- #define N 128
-
-
-
- int main(int argc, char **argv)
- {
- if(argc<3)
- {
- fprintf(stderr,"%s ip post",argv[0]);
- exit(1);
- }
-
- int sockfd;
-
- if((sockfd=socket(AF_INET, SOCK_DGRAM,0))==-1)
- {
- perror("fail to sockfd");
- exit(1);
-
- }
-
- printf("sockfd = %d \n",sockfd);
-
- struct sockaddr_in myaddr;
-
- myaddr.sin_family=AF_INET;
- myaddr.sin_port =htons(atoi(argv[2]));
- myaddr.sin_addr.s_addr = inet_addr(argv[1]);
-
- socklen_t addrlen=sizeof(myaddr);
-
- char buf[N]="";
-
- while(1)
- {
- fgets(buf,N,stdin);
-
- // buf[strlen(buf)-1]='\0'; //有这句话,不会换行
-
- if(sendto(sockfd,buf,N,0,(struct sockaddr*)&myaddr,addrlen)==-1)
- {
- perror("sendto fail");
- exit(1);
-
- }
-
- }
- close(sockfd);
- return 0;
- }

运行结果
头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:将套接字与网络信息结构体绑定
参数:
sockfd:文件描述符,socket的返回值
addr:网络信息结构体
struct sockaddr:通用结构体(一般不用)
使用网络信息结构体 sockaddr_in结构体头文件
#include <netinet/in.h>
结构体函数struct sockaddr_in
addrlen:addr的长度
返回值:
成功:0
失败:‐1
头文件:
#include <netinet/in.h>
函数结构体:
struct sockaddr_in
{
sa_family_t sin_family; //协议族 2字节
in_port_t sin_port; //端口号 2字节
struct in_addr sin_addr; //ip地址 4字节
char sin_zero[8] //填充,不起什么作用 8字节
};struct in_addr
{
in_addr_t s_addr; //ip地址 4字节
};
- #include<stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include<stdlib.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
-
-
- int main(int argc , char **argv[])
- {
-
- int sockfd;
-
- if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
- {
- perror("fail to sockfd");
- exit(1);
-
- }
- printf("sockfd= %d\n",sockfd);
-
- //bind的函数
- struct sockaddr_in mysockaddr;
-
- mysockaddr.sin_family=AF_INET;
- mysockaddr.sin_port =htons(8080);
- mysockaddr.sin_addr.s_addr = inet_addr("10.152.203.29");
-
- socklen_t addrlen = sizeof(mysockaddr);
-
- if(bind(sockfd,(struct sockaddr *)&mysockaddr,addrlen)==-1)
- {
- perror("fail to bind");
- exit(1);
-
- }
-
- }

补充知识:
inet_addr
头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
函数:
in_addr_t inet_addr(const char *cp);
功能:将点分十进制ip地址转化为整形数据
此转换的整形数据也是网络字节序
参数:
cp:点分十进制的IP地址
返回值:
成功:整形数据
atoi函数(字符串转化成整数)
头文件
#include<stdlib.h>
函数int atoi(const char *nptr);
功能
把字符串转化为int类型
返回返回转换后的整型数。
端口号,在我们输入时候,是以字符串形式表达,而我们的结构sockaddr_in 接收的是 整形
因此需要: atoi(端口号) 变为整形数。
只是转为整形数,还不行,由于不同计算机之间通讯,需要转换自己的字节序为网络字节序
因此需要: htons(atoi(端口号));
头文件
#include <sys/types.h>
#include <sys/socket.h>
函数
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,5 struct sockaddr *src_addr, socklen_t *addrlen);
功能:接收数据
参数:sockfd:文件描述符,socket的返回值
buf:保存接收的数据
len:buf的长度
flags:标志位
0 阻塞(基本都设置0)
MSG_DONTWAIT 非阻塞
src_addr:源的网络信息结构体(自动填充,定义变量传参即可)会自动接收对方的ip地址,和端口号,存放此结构体中
addrlen:src_addr的长度
返回值:
成功:接收的字节数
失败:‐1
- #include<stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include<stdlib.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #define N 128
-
- int main()
- {
- char buf[N]="";
-
- struct sockaddr_in recvfrom_addr;
- socklen_t recvfrom_addrlen = sizeof(recvfrom_addr);
-
- while(1)
- {
- if(recvfrom(sockfd,buf,N,0,(struct sockaddr *)&recvfrom_addr,&recvfrom_addrlen)==-1)
- {
-
- perror("fail to recvfrom");
- exit(1);
- }
-
-
- printf("%s\n",buf);
- }
- return 0;
- }

- #include<stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include<stdlib.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
-
-
- #define N 128
- int main(int argc , char *argv[])
- {
- if(argc<3)
- {
-
- fprintf(stderr, "%s ip port ",argv[0]);
- exit(1);
-
- }
-
-
- int sockfd;
-
- if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
- {
- perror("fail to sockfd");
- exit(1);
-
- }
- printf("sockfd= %d\n",sockfd);
-
- struct sockaddr_in mysockaddr;
-
- mysockaddr.sin_family=AF_INET;
- mysockaddr.sin_port =htons(atoi(argv[2]));
- mysockaddr.sin_addr.s_addr = inet_addr(argv[1]);
-
- socklen_t addrlen = sizeof(mysockaddr);
-
-
- if(bind(sockfd,(struct sockaddr*)&mysockaddr,addrlen)<0)
- {
- perror("fail to bind");
- exit(1);
-
- }
-
-
- char buf[N]="";
- struct sockaddr_in recvfrom_addr;
- socklen_t recvfrom_addrlen = sizeof(recvfrom_addr);
-
- while(1)
- {
- if(recvfrom(sockfd,buf,N,0,(struct sockaddr *)&recvfrom_addr,&recvfrom_addrlen)==-1)
- {
-
- perror("fail to recvfrom");
- exit(1);
- }
-
-
- printf("%s\n",buf);
- }
-
- return 0;
- }

运行结果
注意:当我们关掉unbantu服务端程序时,如果在运行同一个端口号,会遇到运行错误。需要换一个端口号才可以运行成功。
当我们发送信息时,先把发送的内容写进buf里,然后再传输给对方。当我们再继续发信息时,原先buf里面装的内容不会清除,如果发的信息多,能覆盖之前buf内容,则输出正常。如果发的信息少,不能覆盖原先的buf的内容,只覆盖前面几个数据,后面原先的数据,照常发送给对方。
- #include<stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include<stdlib.h>
- #include <unistd.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include<string.h>
-
-
- #define N 128
-
-
-
- int main(int argc, char **argv)
- {
- if(argc<3)
- {
- fprintf(stderr,"%s ip post",argv[0]);
- exit(1);
- }
-
- int sockfd;
-
- if((sockfd=socket(AF_INET, SOCK_DGRAM,0))==-1)
- {
- perror("fail to sockfd");
- exit(1);
-
- }
-
- printf("sockfd = %d \n",sockfd);
-
- struct sockaddr_in myaddr;
-
- myaddr.sin_family=AF_INET;
- myaddr.sin_port =htons(atoi(argv[2]));
- myaddr.sin_addr.s_addr = inet_addr(argv[1]);
-
- socklen_t addrlen=sizeof(myaddr);
-
- char buf[N]="";
-
-
- while(1)
- {
- char context[50]="";
- fgets(buf,N,stdin);
-
- // buf[strlen(buf)-1]='\0';
-
- if(sendto(sockfd,buf,N,0,(struct sockaddr*)&myaddr,addrlen)==-1)
- {
- perror("sendto fail");
- exit(1);
-
- }
-
-
-
- if(recvfrom(sockfd,context,sizeof(context),0,(struct sockaddr*)&myaddr,&addrlen)==-1)
- {
- perror("fail to recvfrom");
- exit(1);
- }
-
- printf("from server: %s\n", context);
-
-
- }
- close(sockfd);
-
- return 0;
- }

- #include<stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include<stdlib.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include<string.h>
-
- #define N 128
- int main(int argc , char *argv[])
- {
- if(argc<3)
- {
-
- fprintf(stderr, "%s ip port ",argv[0]);
- exit(1);
-
- }
-
-
- int sockfd;
-
- if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
- {
- perror("fail to sockfd");
- exit(1);
-
- }
- printf("sockfd= %d\n",sockfd);
-
- struct sockaddr_in mysockaddr;
-
- mysockaddr.sin_family=AF_INET;
- mysockaddr.sin_port =htons(atoi(argv[2]));
- mysockaddr.sin_addr.s_addr = inet_addr(argv[1]);
-
- socklen_t addrlen = sizeof(mysockaddr);
-
-
- if(bind(sockfd,(struct sockaddr*)&mysockaddr,addrlen)<0)
- {
- perror("fail to bind");
- exit(1);
-
- }
-
-
- char buf[N]="";
- struct sockaddr_in recvfrom_addr;
- socklen_t recvfrom_addrlen = sizeof(recvfrom_addr);
-
- while(1)
- {
- char text[50]="";
- if(recvfrom(sockfd,buf,N,0,(struct sockaddr *)&recvfrom_addr,&recvfrom_addrlen)==-1)
- {
-
- perror("fail to recvfrom");
- exit(1);
- }
-
- printf("ip:%s ,port:%d\n", inet_ntoa(recvfrom_addr.sin_addr), ntohs(recvfrom_addr.sin_port));
- printf("%s\n",buf);
-
- strcat(text, " *_*");
-
- if(sendto(sockfd, text, sizeof(text), 0, (struct sockaddr *)&recvfrom_addr, addrlen) < 0)
- {
- perror("fail to sendto");
- exit(1);
- }
-
- }
- close(sockfd);
-
- return 0;
- }

运行结果
可以实现多并发
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。