纪念首个毕业设计

本人是专科,然后专升本考上了本科。现在到了毕业的时候了,毕业设计选的是基于树莓派的智能避障小车的设计与实现。一个软硬件都有的设计
在设计过程中我用到了两个在学校学不到的技术,一个是C语言的网络通讯,一个是多线程。
C语言网络通讯用的UDP,当时是别人的代码复制运行…“牛逼”,自己比着葫芦画瓢…“为啥不行??”,然后一顿自闭。
虽然我现在也是半吊子水平,但是想记录一下自己的知识。
首先,我用的是Linux系统进行编程,所以需要先包含头文件:#include<sys/socket.h>
之后创建socket文件描述符int sockfd=socket(AF_INET,SOCK_DGRAM,0);
文件描述符:文件描述符(file descriptor)是内核为了高效管理已被打开的文件所创建的索引,其是一个非负整数(通常是小整数),用于指代被打开的文件,所有执行I/O操作(包括网络socket操作)的系统调用都通过文件描述符。
程序刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。如果此时去打开一个新的文件,它的文件描述符会是3。
第一个参数是IPV4还是IPV6:
AF_INET : IPv4协议;
AF_INET6: IPv6协议;
AF_LOCAL: Unix域协议;
AF_ROUTE:路由套接口;
AF_KEY :密钥套接口。
第二个参数是TCP还是UDP通讯:
SOCK_STREAM:字节流套接字(TCP);
SOCK_DGRAM : 数据报套接字(UDP);
SOCK_RAW : 原始套接口。
procotol: 使用的特定协议,一般使用默认协议(NULL)。
第三个参数一般为0.
之后struct sockaddr_in addr,cli; 其中struct sockaddr_in是声明一个sockaddr_in的结构体,其内容是:
struct sockaddr_in{
  sa_family_t   sin_family;  //地址族,常用AF_INET
  uint16_t     sin_port;   //16位TCP/UDP端口号
  struct in_addr  sin_addr;   //32位IP地址
  char       sin_zero[8]  //不使用
};
struct in_addr{
  in_addr_t    s_addr;   //32位IPV4地址
}
所以之后就是给本地addr数据结构赋值

bzero(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port =htons(port);
addr.sin_addr.s_addr=INADDR_ANY;

bzero(&addr,sizeof(addr));是对addr这个结构体都初始化为0;
port为端口号,INADDR_ANY:转换过来就是0.0.0.0,泛指本机的意思。
然后是绑定,将文件描述符与addr数据结构绑定

int ret =bind(sockfd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in));

首先第一个参数是socket文件描述符
第二个是将addr强制类型转换为struct sockaddr*,具体原因请点击
第三个是输入struct sockaddr_in的空间大小。
bind()成功,返回0;出错,返回-1
之后就可以通过recvfrom()和sendto()进行信息的收发了。

int recvfrom(int s, void *buf, int len, unsigned int flags,struct sockaddr *from, int *fromlen); 

返回值说明:
    成功则返回实际接收到的字符数,失败返回-1,错误原因会存于errno 中。
  参数说明:
    s: socket描述符;
    buf: UDP数据报缓存区(包含所接收的数据);
    len: 缓冲区长度。
    flags: 调用操作方式(一般设置为0)。
    from: 指向发送数据的客户端地址信息的结构体(sockaddr_in需类型转换);
    fromlen:指针,指向from结构体长度值。
示例:

char buff[data_in_len];
socklen_t len=sizeof(cli);
recvfrom(sockfd,buff,sizeof(buff),0,(struct sockaddr*)&cli,&len);

socklen_t相当于int。
之后是sendto()发送:

int sendto(int s, const void *buf, int len, unsigned int flags,const struct sockaddr *to, int tolen);

返回值说明:
    成功则返回实际传送出去的字符数,失败返回-1,错误原因会存于errno 中。
  参数说明:
    s: socket描述符;
    buf: UDP数据报缓存区(包含待发送数据);
    len: UDP数据报的长度;
    flags:调用方式标志位(一般设置为0);
    to:  指向接收数据的主机地址信息的结构体(sockaddr_in需类型转换);
    tolen:to所指结构体的长度;
示例:

char buff[data_out_len];
sendto(sockfd,buff,sizeof(buff),0,(struct sockaddr*)&cli,len);

至此,写完了,感觉自己还是菜emmm
下面上我那小车的代码,里面还有多线程的东西
###很菜,勿喷

#include <stdio.h>
#include<string>
#include<iostream>
#include<pthread.h>
#include<sys/socket.h>

#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
bool log=0;
typedef struct
{
	int sockfd;
	struct sockaddr_in cli;
	char *fin;
	char *fout;
}Data;
#define port 10000

using namespace std;
void* runfin(void *arg){
	Data *data=(Data*)arg;
	socklen_t len=sizeof(data->cli);
	char buff[data_in_len];
	struct sockaddr_in temp_cli;
	cout<<"准备接收:\n";
	recvfrom(data->sockfd,buff,sizeof(buff),0,(struct sockaddr*)&(data->cli),&len);
	log=1;
	while(1){
	pthread_mutex_lock(&indata_mutex);
	strcpy(data->fin,buff);
	pthread_mutex_unlock(&indata_mutex);
	recvfrom(data->sockfd,buff,sizeof(buff),0,NULL,&len);
	}
	return NULL;
}
void* runfout(void *arg){
	Data *data=(Data*)arg;
	socklen_t len=sizeof(data->cli);
	char buff[data_out_len];
	while(1)
	{
	sleep(1);
	if(log)
	{
	pthread_mutex_lock(&outdata_mutex);
	strcpy(buff,data->fout);
	pthread_mutex_unlock(&outdata_mutex);
	sendto(data->sockfd,buff,sizeof(buff),0,(struct sockaddr*)&(data->cli),len);
	}
	}
	return NULL;
}
int feedback(char *fin,char *fout){
	pthread_t Fin,Fout;

	int sockfd=socket(AF_INET,SOCK_DGRAM,0);
	struct sockaddr_in addr,cli;
	bzero(&addr,sizeof(addr));
	addr.sin_family=AF_INET;
	addr.sin_port =htons(port);
	addr.sin_addr.s_addr=INADDR_ANY;
	int ret =bind(sockfd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in));
	if(0>ret)
	{
	printf("bind\n");
	return -1;
	}
	Data *data=(Data*)malloc(sizeof(Data));
	data->sockfd=sockfd;
	data->fin=fin;
	data->fout=fout;
	bzero(&data->cli,sizeof(data->cli));
	socklen_t len=sizeof(data->cli);
	pthread_create(&Fin,NULL,runfin,(void*)data);
	pthread_create(&Fout,NULL,runfout,(void*)data);
	//pthread_join(Fin,NULL);
	//pthread_join(Fout,NULL);
	return 0;
}
/*int main()
{
	char fin[data_len]={"523"};
	char fout[data_len]={"123\n"};
	feedback(fin,fout);
	return 0;
}*/

这里面的发送会一直循环…毕竟要实时获得信息。这只是其中一个头文件的代码,还有控制端和PWM调速的没发。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值