RS232和socket网络通信中的字符串、整型

1.我们先要明确,通信中我们传递的是什么?
数字信号:010101
模拟信号:高低电平

我们想要发送字符串“YYDS”
我们需要找到字符串和0101数字信号对应
字符串在储存时,需要转换成ASCII码,然后将ASCII储存。

“YYDS”
0x59 0x59 0x44 0x53
01011001 01011001 01000100 01010011

其中“1011001 1011001 1000100 1010011”便是YYDS的数字信号,当然,如果你想发一个int a = 188113491,那么你发的也是1011001……。

可以看出,不论你发字符串还是发整型,都是发的比特流。比特流只表示0101,如果不指明数据类型,其实它没有任何意义。

因此,你发送一个字符串或者整型,你只需要把你的数据转换成数字信号,并存放在发送缓存中(这一步大部分是不需要我们操作的,我们只需要将我们的数据按顺序放置在缓存中就可以了),接收方接收到数字信号后,需要按照数据类型,以及大端小端,将比特流拆分,整理,以相应的长度保存到相应变量中。
例如发送的是:char、int、int,char
那么接收:前8位比特通过ascii,转换为字符;9-24比特,直接转为整型;25-40比特,直接转为整型;41-48比特通过ascii,转为字符。

通信中传输的是比特流,你想发,你就想办法把数据灌到比特流中,你想收,你就将接收到的比特流按对方的协议,解析成能正确提取信息的结构。

2.c语言结构体定义及转换为字符串
定义:

typedef struct {
    char test1;         //seq: 1    分割符
    int year;          //seq: 2    年
} __attribute__ ((__packed__)) AV_DATA;

创建结构体指针(指向结构体首地址):
当然,你也可以直接用结构体,那样只是更费资源。

ARV_DATA *data0;

初始化结构体

data0 = (ARV_DATA *)malloc(sizeof(ARV_DATA));
memset(data0, 0, sizeof(ARV_DATA));

结构体赋值,这里用的结构体指针,所用直接使用“->”

void makedata(ARV_DATA *data)
{   
    data->test1 ='@';
    data->year =2022;
}

说是转化成字符串,其实是将整个结构体的所有数据,按照一字节转为一字符分开。
结构体的数据:'@'2022
结构体的16进制:40 00 00 07 E6
结构体的数字信号:0010 1000 0000 0000 0000 0000 0000 0111 1110 0110

如果将其转化为字符串(这里只和大小端有关系,如果不考虑大小端)

char *buf;
buf = (char *)malloc(MAX_DATA_BUF);
memset(buf, 0, MAX_DATA_BUF);
memcpy(buf, data0, sizeof(ARV_DATA));

字符串的数字信号:0010 1000 0000 0000 0000 0000 0000 0111 1110 0110
如果按照字符显示:
‘@’,‘NUL’,‘NUL’,‘BEL’,‘æ’
这里如果用

printf("Char:%s\n",buf);

则输出

@

其他都是不可打印字符

3.Socket网络通信
我们调试Socket时,更多的情况下会用自己的电脑建立一个客户端,一个服务器端,自己给自己发。
这里,有一个比较好用的IP:127.0.0.1(保留地址),发给这个IP的。当IP层接收到目的地址为127.0.0.1的数据包时,不调用网卡驱动进行二次封装,而是立即转发到本机IP层进行处理,可实现计算机的自发自收。

这里以Linux的UDP为例子
1)不管发送端还是结构端,都需要创建一个结构体sockaddr_in

struct sockaddr_in localSockAddr;

用该结构来绑定IP和端口,或者给IP和端口发送数据

void init()
{
	int localPortNum = 8006;
	char localIpAddr[20] = "127.0.0.1";
    memset(&localSockAddr, 0, sizeof(localSockAddr));
    localSockAddr.sin_family=AF_INET;
    localSockAddr.sin_addr.s_addr=inet_addr(localIpAddr);
    localSockAddr.sin_port=htons(localPortNum);
}

2)接收端
①创建套接字描述符

int localSockfd = socket(AF_INET, SOCK_DGRAM, 0);

AF_INET:为使用常用的IPv4协议
SOCK_DGRAM:为创建UDP套接字
0:前面已经指明UDP套接字,后面默认

②绑定IP和端口号,其实绑定不是太准确,可以说是告诉程序,你需要去监听的ip和port。
如果你是一台电脑,绑定自己的IP或者127.0.0.1,如果你是有好几个网卡的服务端,你就需要选择绑定哪个IP了。

socklen_t g_sinSize = sizeof(localSockAddr);
int ret = bind(localSockfd, (struct sockaddr*)&localSockAddr, g_sinSize);

③监听
监听需要添加循环,让其一直处于监听状态。有了循环,如果你不用多线程那么,程序就会卡在循环中,因此需要为它独自建立一个线程,以让其循环不干扰其他程序的运行。
Ⅰ、建立接收buf

char socket_read_buf[1024];

Ⅱ、建立循环

while (1) {
    		memset(socket_read_buf, 0, sizeof(socket_read_buf));
            memset(socket_read_buf, 0, sizeof(socket_read_buf));
        if ((len = recvfrom(localSockfd, socket_read_buf, MAX_DATA_BUF, 0,(struct sockaddr *)&reSockAddr,&g_sinSize)) <= 0) {
            usleep(100000); // 100ms
        } else {
        	printf("Receive From Socket Success: %d from port :%d\n", len,reSockAddr.sin_port);
        }

这里大家可能注意到了二郎写了一个
(struct sockaddr *)&reSockAddr
其一:建立一个新的sockaddr_in结构体

struct sockaddr_in reSockAddr;

其二:将该结构体的首地址强制转换成sockaddr指针
因为recvfrom需要这样的一个指针
其三:这里新建结构体是因为该结构体记录发送端的ip和port,而并非指明自己的ip和port

3)发送端
①创建套接字描述符

int localSockfd1 = socket(AF_INET, SOCK_DGRAM, 0);

②发送数据
这里为了测试,因此用的循环,正常使用按自己的需要来写

while(1)
    {
        rtn = sendto(localSockfd1, data0, tempMsgLen, 0,(struct sockaddr *)&localSockAddr,g_sinSize);
        printf("Socket write size %d\n", rtn);
        sleep(5);
}

这里写了localSockAddr,此处为接收端的套接字结构体,告诉sendto往哪个套接字去发送。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值