数据报套接字

本文详细介绍了UDP通信中数据报套接字的使用,包括socket函数创建套接字、字节序转换函数htonl/htons/ntohl/ntohs、bind函数绑定地址、inet_pton和inet_ntop进行IP地址转换、recvfrom和sendto进行数据收发,以及本地回环测试案例。内容涵盖了从基本概念到实际操作的全过程。
摘要由CSDN通过智能技术生成

数据报套接字用于实现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_INET
    sa_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	13

struct 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	128

int 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   128

int 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的终端就可以显示了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值