数据报套接字"/>
数据报套接字
数据报套接字用于实现UDP通信
1.socket()
int socket(int domain,int type,int protocol); // 失败返回-1
domain - 协议族:(1)AF_UNIX,AF_LOCAL 本地通讯(2)AF_INET IPV4 (3) AF_INET6 IPV6
type - 实现方式: (1)SOCK_STREAM 流式 (2)SOCK_DGRAM 报式
protocol - 协议:一般为0
2.htonl / htons / ntohl / ntohs
字节序:
字节序与网络字节序转换
uint32_t htonl(uint32_t hostlong); //32位主机字节序转换到网络字节序
uint16_t htons(uint16_t hostshort); //16位主机字节序转换到网络字节序
uint32_t ntohl(uint32_t netlong); //32位网络字节序转换到主机字节序
uint16_t ntons(uint16_t netshort); // 16位网络字节序转换到主机字节序
大端的网络字节序和主机字节序一致,不需要使用以上四个函数。如果 htonl(1)==1则为大端模式
3.bind()将套接字与地址关联
int sockfd = socked(int domain,int type,int protocol)
int bind(sockfd, const struct sockaddr *addr, socklen_t addrlen);
addlen:协议地址addr空间大小
addr - 协议地址,依赖于domain的地址信息
以AF_INET为例,它的协议地址类型为
struct sockaddr_in{//协议族:AF_INETsa_family_t sin_family;//端口in_port_t sin_port;//IP地址,不能是点分式192.168.20.22,需要是大整数,因此要格式转换struct in_addr sin_addr;
};struct in_addr{//大整数形IP地址uint32_t s_addr;
};
4.IP类型转换:inet_pton() / inet_ntop()
(1)inet_pton():点分式转大整数形
int inet_pton(int af,const char *src,void *dst)
af:协议族,只能是AF_INET或AF_INET6,即IPv4或IPv6
src:点分式的IP地址
dst:转换之后的存储空间
成功返回1,失败返回-1
(2)inet_ntop():大整数形转点分式
size:dst指向的空间大小
成功返回dst首地址,失败返回NULL
5.接收recvfrom()
ssize_t recvfrom(sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addlen);
buf:接收信息存储地址
len:接受信息存储空间大小
flags:特殊要求,一般为0
src_addr:发送端地址
addrlen:发送端地址空间大小
成功返回接收到的字节数,失败返回-1
6.发送sendto()
ssize_t sendto(sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
buf:发送数据信息存储地址
len:发送数据信息存储空间
flags:特殊要求
dest_addr:接收端的地址
addlen:接收端地址空间大小
成功返回发送的字节数,失败返回-1
7.本地回环测试
(1)proto.h
#ifndef PROTO_H__
#define PROTO_H__#include <stdint.h>#define RCVER_PORT "2989" #define NAMESIZE 13struct msg_st
{uint8_t name[NAMESIZE];uint32_t math;uint32_t chinese;
}__attribute__((packed));#endif
(2)rcver.c
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>#include "proto.h"#define IPSTRSIZE 128int main()
{int sd;struct sockaddr_in laddr,raddr;struct msg_st rbuf;socklen_t raddr_len;char ipstr[IPSTRSIZE];sd = socket(AF_INET,SOCK_DGRAM,0/*IPPROTO_UDP*/);if(sd < 0){perror("socket()");exit(1);}laddr.sin_family = AF_INET;laddr.sin_port = htons(atoi(RCVER_PORT));inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr);if(bind(sd,(void *)&laddr,sizeof(laddr)) < 0){perror("bind()");exit(1);}raddr_len = sizeof(raddr);while(1){if(recvfrom(sd,&rbuf,sizeof(rbuf),0,(void *)&raddr,&raddr_len) < 0){perror("recvfrom()");exit(1);}inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE); printf("-----MESSAGE FROM:%s:%d-------\n",ipstr,ntohs(raddr.sin_port));printf("NAME:%s\n",rbuf.name);printf("MATH:%d\n",ntohl(rbuf.math));printf("CHINESE:%d\n",ntohl(rbuf.chinese));} close(sd);exit(0);
}
(3)snder.c
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>#include "proto.h"#define IPSTRSIZE 128int main(int argc,char *argv[])
{int sd;struct sockaddr_in raddr;struct msg_st sbuf;if(argc < 2){fprintf(stderr,"Usage...\n");exit(1);}sd = socket(AF_INET,SOCK_DGRAM,0/*IPPROTO_UDP*/);if(sd < 0){perror("socket()");exit(1);}//bind();memset(&sbuf,'\0' ,sizeof(sbuf));strcpy(sbuf.name,"Alan");sbuf.math = htonl(rand()%100);sbuf.chinese = htonl(rand()%100);raddr.sin_family = AF_INET;raddr.sin_port = htons(atoi(RCVER_PORT));inet_pton(AF_INET,argv[1],&raddr.sin_addr);if(sendto(sd,&sbuf,sizeof(sbuf),0,(void *)&raddr,sizeof(raddr)) < 0){perror("sendto()");exit(1);}puts("OK");close(sd);exit(0);}
gcc rcver.c proto.h -o rcver 编译
./rcver 运行
打开新的终端,输入netstat -anu,0.0.0.0:2989出现
在新的终端继续输入:
gcc snder.c proto.h -o snder 编译
./snder 127.0.0.1 运行
在rcver的终端就可以显示了
更多推荐
数据报套接字
发布评论