文章目录
- Udp编程接口
- socket():创建套接字
- bind ():将套接字绑定到指定的网络地址
-
- recvfrom()接收一个数据报并保存源地址,从数据报套接字接收数据
-
- sendto():按照指定目的地向数据报套接字发送数据
-
- 实例代码
- udp_server.cc
- ucp_client.cc
Udp编程接口
socket():创建套接字
int socket(AF_INET,SOCK_DGRAM,0);
-
参数domain 用来说明网路程序所在的主机采用的是那种通信协议簇,这些协议族再头文件<sys/socket.h>中定义
-
AF_INET //表示IPv4网络协议
-
AF_INET6 //IPv6网络协议
-
参数type 用来指明创建的套接字类型,
-
SOCK_STREAM:流式套接字,面向连接可靠的通信类型
-
SOCK_DGRAM:数据报套接字,非面向连接和不可靠的通信类型
-
SOCK_RAW:原始套接字,用来直接访问IP协议
-
参数protocol 指定套接字使用的协议,一般采用默认值0,表示让系统根据地址格式和套接字类型,自动选择一个合适的协议
-
返回值:
-
调用成功就创建了一个新的套接字并返回它的描述符,在之后对该套接字的操作中都要借助这个文件描述符,
-
否则返回-1(<0) 表示套接字出错.应用程序可调用WSAGetLastError() 获取相应的错误代码
bind ():将套接字绑定到指定的网络地址
使用这个函数前需要将服务器的ip和端口号赋值到结构体sockaddr_in中
使用bind()函数前的准备工作
struct sockaddr{
u_short sa_family;
char sa_data[14]
};
struct sockadd_in{
short int sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
struct in_addr{
unsigned long s_addr;
};
#include<netinet/in.h>
int bind(int sockfd,const struct sockaddr* addr,socklen_t addrlen);
- 最后在函数调用的时候,将这个结构强制转换成sockaddr类型
本机字节序和网络字节序
-
本机字节序在不同的计算机中,存放多字节值的顺序是不一样的,有的是从低到高,有的是从高到低.计算机中的多字节数据的存储顺序称为本机字节顺序.
-
网络字节序:在网络协议中,对多字节数据的存储,有它自己的规定。多字节数据在网络协议报头中的存储顺序,称为网络字节序.在套接字中必须使用网络字节序
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200620154133146.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2phY2tfd2FuZzEyODgwMQ==,size_16,color_FFFFFF,t_70)
所以把IP地址和端口号装入套接字时,我们需要将本机字节序抓换成网络字节序,在本机输出时,我们需要将它们从网络字节序转换成本机字节序
-
套接字编程接口专门为解决这个问题设置了4个函数
-
1.htons():短整数本机顺序转换为网络顺序,用于端口号
-
2.htonl():长整数本机顺序转换成网络顺序,用于IP地址
-
3.ntohs():短整数网络顺序转换为本机顺序,用于端口号
-
4.ntohl():长整数网络顺序转换为本机顺序,用于IP地址
这4个函数将被转换的数值作为函数的参数,函数返回值作为转换后的结果
在Internet中,IP地址常常是用点分十进制的表示方法,但在套接字中,IP地址是无符号的长整型数,套接字编程接口设置了两个函数,专门用来两种形式IP地址的转换
unsigned long inet_addr(const char* cp);
char* inet_ntoa(struct in_addr in)
recvfrom()接收一个数据报并保存源地址,从数据报套接字接收数据
调用格式
int recvfrom(SOCKET s,char *buf,int len,int falgs,
struct sockaddr* from, int* fromlen);
-
参数s:接收端的数据报套接字描述符,包含接收方的网络地址,从这个套接字接收数据报
-
参数buf:字符串指针,指向用户进程的接收缓冲区,用来接收从套接字收到的数据报
-
参数len:用户接收缓冲区的长度,制定了所能接收的最大字节数
-
参数flags:接收的方式,一般置为0.
-
参数from: 指向sockaddr 结构的指针,实际上是一个出口参数,当本次调用成功执行后,在这个结构中返回了发送方的网络地址,包括对方的IP地址和端口号
-
参数fromlen:整数型指针,也是一个出口型参数,本调用结束时,返回存在from中的网络地址长度
-
返回值: 如果正确接收,则返回实际收到的字节数,如果出错,返回SOCKET_ERROR,应用程序可通过WSAGetLastError()获取相应的错误代码
函数功能
sendto():按照指定目的地向数据报套接字发送数据
调用格式
int sendto(SOCKET s,char* buf,int len,int flags,struct sockaddr* to,
int tolen)
-
参数s:发送方的数据报套接字 描述符,包含发送方的网络地址,数据报通过这个套接字向对方发送
-
参数buf:指向用户进程发送缓冲区的字符串指针,该缓冲区包含将要发送的数据,
-
参数len:用户发送缓冲区中要发送的数据的长度,是可以发送的最大字节数
-
参数flags: 指定函数的执行方式,一般置为0.
-
参数to:指向sockaddr 结构的指针,指定接收数据报的目的套接字的完整的网络地址
-
参数tolen: to的地址长度,等于sizeof(struct sockaddr)
-
返回值:如果发送成功,则返回实际发送的字节数,注意这个数字可能小于len中所规定的长度,如果出错返回错误码
函数功能
本函数专用于数据报套接字,用来向发送端的本地套接字发送一个数据报.套接字会将数据下交给传输层的UDP,由它向对方发送.
实例代码
udp_server.cc
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<cstring>
#include<unistd.h>
int main(){
int sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock<0){
perror("socket");
return 1;
}
sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_addr.s_addr = inet_addr("0.0.0.0");
addr.sin_port=htons(8080);
int ret=bind(sock,(sockaddr*)&addr,sizeof(addr));
if(ret<0){
perror("bind");
return 1;
}
printf("server start ok!\n");
while(true){
sockaddr_in peer;
socklen_t len=sizeof(peer);
char buf[1024]={0};
ssize_t n= recvfrom(sock,buf,sizeof(buf)-1,0,(sockaddr*)&peer,&len);
printf("客户端发来消息:%s\n",buf);
printf("请输入回复内容:");
if(n<0){
perror("recvfrom");
continue;
}
buf[n]='\0';
char buf2[1024]="0";
scanf("%s",buf2);
n=sendto(sock,buf2,strlen(buf2),0,(sockaddr*)&peer,len);
if(n<0){
perror("sendto");
continue;
}
printf("[%s:%d] buf: %s\n",inet_ntoa(peer.sin_addr),
ntohs(peer.sin_port), buf2);
}
close(sock);
return 0;
}
ucp_client.cc
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<cstring>
#include<unistd.h>
int main(int argc,char *argv[]){
int sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock<0){
perror("socket");
return 1;
}
sockaddr_in server_addr;
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=inet_addr(argv[1]);
server_addr.sin_port=htons(8080);
while(1){
char buf[1024]={0};
printf("请输入一段内容:");
fflush(stdout);
scanf("%s",buf);
sendto(sock,buf,strlen(buf),0,
(sockaddr*)&server_addr,sizeof(server_addr));
char buf_output[1024]={0};
recvfrom(sock,buf_output,sizeof(buf_output)-1,0,
NULL,NULL);
printf("客户端回应:%s\n",buf_output);
}
return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)