报式套接字通讯实例

报式套接字通讯实例

使用套接字通讯流程

被动端(先运行)
1、取得SOCKET
2、给SOCKET取得地址
3、收/发消息
4、关闭SOCKET

主动端
1、取得SOCKET
2、给SOCKET取得地址(可省略)
3、发/收消息
4、关闭SOCKET

各部分代码实现

proto.h代码如下:

#ifndef PROTO_H__
#define PROTO_H__

//定义端口号
#define RCVPORT     "1989"

#define NAMESIZE    11

//__attribute__((packed))表示结构体取消内存对齐
struct msg_st
{
    uint8_t name[NAMESIZE];
    uint32_t math;
    uint32_t chinese;
}__attribute__((packed));

#endif

rcvder.c代码如下:


#include 
#include 
#include 
#include 
#include 
#include 

#include "proto.h"

#define IPSTRSIZE   40

int main()
{

    int sd;
    //定义我端的地址laddr
    struct sockaddr_in laddr,raddr;
    struct msg_st rbuf;
    socklen_t raddr_len;
    char ipstr[IPSTRSIZE];

    //使用AF_INET协议族中的默认协议(0),实现SOCK_DGRAM
    sd = socket(AF_INET,SOCK_DGRAM,0);
    if(sd < 0)
    {
        perror("socket()");
        exit(0);
    }

    laddr.sin_family = AF_INET;
    //因为端口要在网络传输,所以使用htons转换,将本地(host)转为网络(net),宽度为short
    laddr.sin_port = htons(atoi(RCVPORT));
    /*inet_pton将IP地址的点分式转为整数
    int inet_pton(int af,const char *src,void *dst)
    参数:
    af  协议族,要么是IPV4(AF_INET)要么是IPV6(AF_INET6)
    src 要转换的IP地址
    dst 转换后要放置的地址处
    */
    //"0.0.0.0"表示匹配的任意地址
    inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr);

    //我端的地址和地址长度
    if(bind(sd,(void *)&laddr,sizeof(laddr)) < 0)
    {
        perror("bind()");
        exit(1);
    }

    while(1)
    {
        /*
        ssize_t recv(int sockfd,void *buf,size_t len,int flags)
        这个适用于流式套接字,一对一通讯
        
        ssize_t recvfrom(int sockfd,void *buf,size_t len,int flags,
                        struct sockaddr *src_addr,socklen_t *addrlen)
        recvfrom是适用于报式套接字,非一对一的通讯,要记录传输数据地址从哪里来的
        */
       /*
       一定要初始化raddr_len的大小,否则回造成第一次打开地址不对,后面会对

       */
        raddr_len = sizeof(raddr);
        recvfrom(sd,&rbuf,sizeof(rbuf),0,(void *)&raddr,&raddr_len);
        //使用inet_ntop();函数将ip大整数转为点分式
        inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE);
        printf("----MESSAGE FROM IP: %s port: %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);
}

编译执行结果如下:

使用netstat -anu命令查看udp网络状态,如果查看tcp使用netstat -ant命令,结果如下1989端口已经打开。

报式套接字通讯实例_第1张图片

snder.c代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "proto.h"

int main(int argc,char *argv[])
{

    int sd;
    //将待发送的内容放到sbuf中
    struct msg_st sbuf;
    struct sockaddr_in raddr;

    if(argc < 2)
    {
        fprintf(stderr,"Usage is short 2\n");
        exit(1);
    }

    sd = socket(AF_INET,SOCK_DGRAM,0);
    if(sd < 0)
    {
        perror("socket()");
        exit(1);
    }


    //bind();
    /*
        ssize_t send(int sockfd,const void *buf,size_t len,int flags);
        这个是用于流式套接字,因为式一对一通讯
        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选择默认
        dest_addr   目的地址
        addrlen 的地址的大小
        返回值
        成功  送出去的字符个数
        失败 -1
    */

    //填充sbuf要发送的数据
    strcpy(sbuf.name,"Alan");
    sbuf.math = htonl(rand()%100);
    sbuf.chinese = htonl(rand()%100);

    //设置远端的地址,分别设置协议族、端口、IP地址
    raddr.sin_family = AF_INET;
    raddr.sin_port = htons(atoi(RCVPORT));
    inet_pton(AF_INET,argv[1],&raddr.sin_addr);

    if(sendto(sd,&sbuf,sizeof(sbuf),0,(void *)&raddr,sizeof(raddr)) < 0)
    {
        perror("sento()ssfd");
        exit(1);
    }

    puts("OK!");

    close(sd);

    exit(0);
}

编译运行结果如下:
1657709179287
使snder与rcver建立通信,先执行./rcver,再执行./snder,执行结果如下:
编译运行结果如下:
1657709760180

你可能感兴趣的:(网络编程,网络,linux)