目录
1. LCD换自己喜欢的颜色
2. LCD换个图案
3. LCD换张图片
4.网线登录
ifconfig eth0 192.168.5.9
5.触屏电子相册
6.网络编程(TCP通信)
7.网络编程(UDP通信)
说实话,对于这个粤嵌的实训,真的有很多想吐槽的地方,以下就是粤嵌给的一块板子,屏幕已经碎了,只有一根串口线(甚至是RS232,tm的)和一根DC电源(可能是为了省成本,要我就整个TYPEC供电了),它甚至一条MIRCOusb都不给(接OTG,后来我发现adb传输用不了,可能是这块板子OTG口需要特定的驱动,是的,我没资料),网线也没给,tftp,nfs都没法用,后面发现它竟然是用板载的一个rx工具(当时真是知识盲区),对比我用的一块全志的T113的板子,这块板子真的寄。
吐槽完就进入正题吧,就是关于整个实训的各个实验:
1. LCD换自己喜欢的颜色
对于传输文件,我这里就统一用TFTP传输了
环境配置过程:
1.在windows环境下创建一个share文件,就用来存需要传到开发板的文件。
2.关掉防火墙(记得把那些360之类的也关了,下面的是防火墙关闭工具)
链接:https://pan.baidu.com/s/1R5ycBw-_kbUw-jruMJyZmQ
提取码:1234
3.TFTP工具配置
链接:https://pan.baidu.com/s/18gele0YKJ_-J2cbJhg-QuQ
提取码:1234
就改这两个,一个是share文件夹的路径,一个是本机的ip
4.把开发板IP改成与本机IP同一网段(因为我本机IP是192.168.5.10,开发板就改成192.168.5.9)
ifconfig eth0 192.168.5.9
5.尝试ping通本机IP
6.TFTP传输
我在share文件夹下放了一张BMP格式的图片
tftp 192.168.5.10 -g -r func.bmp
参数的详情见这篇博客 Linux命令之tftp常用参数说明_小小小羊羊羊的博客-CSDN博客_tftp参数这玩意主要是快啊,比rx快太多了,如果你还是没配出来,那建议参考韦东山老师的配置双网卡的教程走一遍,其实我在玩粤嵌这块板子前是先去玩了T113的开发板,试着走驱动开发方向,但没办法,既然学校强制学习应用开发,那就来吧!(鸡汤)
然后还是正题,就是显示个喜欢的颜色,很简单哈。
代码贴出来,扔到ubuntu拿交叉编译工具链跑就行
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
//ssize_t write(int fd, const void *buf, size_t count);
//int open(const char *pathname, int flags);
int main()
{
//1.打开屏幕
int fd=0; //接受open的返回值
fd=open("/dev/fb0", O_RDWR);
if(fd==-1) //做错误判断
{
perror("open hello.c fail");
}
//2.写入颜色数据
int w_ret=0;
int i=0;
int j=0;
unsigned int color[480][800]={0};
for(i=0;i<480;i++)
{
for(j=0;j<800;j++)
{
color[i][j]=0xff0000; //红色
}
}
w_ret=write(fd, color, 480*800*4);
if(w_ret==-1)//做错误判断
{
perror("write fail");
}
//3.关闭文件
close(fd);
}
arm-linux-gnueabi-gcc -o LCD LCD.c
因为用的是自己的编译环境就直接搞了,编译出来的程序文件已经框出来了。
TFTP传输进去开发板,然后添加运行权限运行。
tftp 192.168.5.10 -g -r LCD1
chmod 777 LCD1
./LCD1
代码效果如下,实在有点简单,代码就不改了。
2. LCD换个图案
代码贴出来,操作也是和上面那个实验类似。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
//ssize_t write(int fd, const void *buf, size_t count);
//int open(const char *pathname, int flags);
int main()
{
//1.打开屏幕
int fd=0; //接受open的返回值
fd=open("/dev/fb0", O_RDWR);
if(fd==-1) //做错误判断
{
perror("open hello.c fail");
}
//2.写入颜色数据
int w_ret=0;
int i=0;
int j=0;
unsigned int color[480][800]={0};
for(i=0;i<480;i++)
{
for(j=0;j<800;j++)
{
if((j-400)*(j-400)+(i-240)*(i-240)<=200*200) //(x-x0)*(x-x0) + (y-y0)*(y-y0) =r*r
{
color[i][j]=0xff0000; //红色
}
else
{
color[i][j]=0x000000; //黑色
}
}
}
w_ret=write(fd, color, 480*800*4);
if(w_ret==-1)//做错误判断
{
perror("write fail");
}
//3.关闭文件
close(fd);
}
arm-linux-gnueabi-gcc -o LCD2 LCD.c
tftp 192.168.5.10 -g -r LCD2
chmod 777 LCD2
./LCD2
效果如上,因为前面的三个LCD实验比较简单,过得快一点了,后面的网络编程才是重头戏
3. LCD换张图片
代码贴在这里,图片用的是我在实验一用TFTP传输过去的那张,像素为800*480,必须为BMP格式,且必须命名(func.bmp)图片不是我做的,虽然我会,但我不想自己整一张了,就沿用别人发的图片吧
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
//off_t lseek(int fd, off_t offset, int whence);
//ssize_t read(int fd, void *buf, size_t count);
//ssize_t write(int fd, const void *buf, size_t count);
//int open(const char *pathname, int flags);
int main()
{
//1.打开屏幕
int fd=0; //接受open的返回值
fd=open("/dev/fb0", O_RDWR);
if(fd==-1) //做错误判断
{
perror("open fb0 fail");
}
//打开图片
int bmp_fd=0; //接受open的返回值
bmp_fd=open("./func.bmp", O_RDWR);
if(bmp_fd==-1) //做错误判断
{
perror("open func.bmp fail");
}
//2.偏移54字节
lseek(bmp_fd,54,SEEK_SET);
//3.读取像素数据 800*480
unsigned char bmp[800*480*3]={0};
read(bmp_fd,bmp,sizeof(bmp));
//4.数据处理
/*
bmp[0]--B
bmp[1]--G
bmp[2]--R
bmp[3]--B
....
lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16;
lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16;
lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16;
*/
unsigned int lcd[800*480]={0};
int i=0;
int j=0;
for(i=0;i<800*480;i++)
{
lcd[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16;
}
//5.写入屏幕
int w_ret=0;
w_ret=write(fd, lcd, sizeof(lcd));
if(w_ret==-1)//做错误判断
{
perror("write fail");
}
//6.关闭文件
close(bmp_fd);
close(fd);
}
arm-linux-gnueabi-gcc -o LCD3 LCD.c
tftp 192.168.5.10 -g -r LCD3
chmod 777 LCD3
./LCD3
效果如上,可以看到图片是颠倒的。下面贴个如何把图片正过来的代码。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
//off_t lseek(int fd, off_t offset, int whence);
//ssize_t read(int fd, void *buf, size_t count);
//ssize_t write(int fd, const void *buf, size_t count);
//int open(const char *pathname, int flags);
int main()
{
//1.打开屏幕
int fd=0; //接受open的返回值
fd=open("/dev/fb0", O_RDWR);
if(fd==-1) //做错误判断
{
perror("open fb0 fail");
}
//打开图片
int bmp_fd=0; //接受open的返回值
bmp_fd=open("./func.bmp", O_RDWR);
if(bmp_fd==-1) //做错误判断
{
perror("open func.bmp fail");
}
//2.偏移54字节
lseek(bmp_fd,54,SEEK_SET);
//3.读取像素数据 800*480
unsigned char bmp[800*480*3]={0};
read(bmp_fd,bmp,sizeof(bmp));
//4.数据处理
/*
bmp[0]--B
bmp[1]--G
bmp[2]--R
bmp[3]--B
....
lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16;
lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16;
lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16;
*/
unsigned int temp[800*480]={0};
unsigned int lcd[800*480]={0};
int i=0;
int j=0;
for(i=0;i<800*480;i++)
{
temp[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16;
}
for(i=0;i<480;i++)
{
for(j=0;j<800;j++)
{
lcd[(480-1-i)*800+j]=temp[i*800+j];
}
}
//5.写入屏幕
int w_ret=0;
w_ret=write(fd, lcd, sizeof(lcd));
if(w_ret==-1)//做错误判断
{
perror("write fail");
}
//6.关闭文件
close(bmp_fd);
close(fd);
}
这里省去交叉编译的过程图
效果图如上,其实就是把图反着写入。
在这里把执行的程序文件放上来,大伙自己烧板子自己试哈
链接:https://pan.baidu.com/s/1BuQ5Q2FEGbgdJ1yEr4o86w
提取码:1234
4.网线登录
啧...我觉得这个可能没太大必要,虽然好像可以省一个串口,但还不如串口换成个带5V的TYPEC,也是两条线,搞这个不如整个WiFi模块远程无线调试,我不做了,但里面有一个过程比较有价值,就是更改开机脚本的
vi /etc/profile
ifconfig eth0 192.168.5.9
5.触屏电子相册
我靠,晴天霹雳,完成这东西需要整多几张图,太难受了
然后在图画另存为bmp格式就行,我做的是这三张。
下面贴出代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/input.h>
//void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
//off_t lseek(int fd, off_t offset, int whence);
//ssize_t read(int fd, void *buf, size_t count);
//ssize_t write(int fd, const void *buf, size_t count);
//int open(const char *pathname, int flags);
//函数声明
int show_bmp(const char *bmpname);
int show_anybmp(const char *bmpname);
int show_anywherebmp(int x0,int y0,const char *bmpname);
int get_xy(int *x,int *y);
int main()
{
int x=-1;
int y=-1;
int tmp=0;
char photo[][30]={"./1.bmp","./2.bmp","./3.bmp"};
//1.显示主界面
show_anybmp("./func.bmp"); //规则界面
while(1)
{
//2.获取坐标
get_xy(&x,&y);
if(x>=400) //下一张
{
tmp=(tmp+1)%3;
show_bmp(photo[tmp]);
}
else if(x<400) //上一张
{
tmp=tmp-1;
if(tmp==-1){
tmp=2;
}
show_bmp(photo[tmp]);
}
//用完坐标得清零 坐标
x=-1;
y=-1;
}
}
//函数实现
//显示800*480的图片
int show_bmp(const char *bmpname)
{
//1.打开屏幕
int fd=0; //接受open的返回值
fd=open("/dev/fb0", O_RDWR);
if(fd==-1) //做错误判断
{
perror("open fb0 fail");
}
//建立屏幕映射
unsigned int* lcd = mmap(NULL, 800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
//打开图片
int bmp_fd=0; //接受open的返回值
bmp_fd=open(bmpname, O_RDWR);
if(bmp_fd==-1) //做错误判断
{
perror("open func.bmp fail");
}
//2.偏移54字节
lseek(bmp_fd,54,SEEK_SET);
//3.读取像素数据 800*480
unsigned char bmp[800*480*3]={0};
read(bmp_fd,bmp,sizeof(bmp));
//4.数据处理
/*
bmp[0]--B
bmp[1]--G
bmp[2]--R
bmp[3]--B
....
lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16;
lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16;
lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16;
*/
unsigned int temp[800*480]={0};
int i=0;
int j=0;
for(i=0;i<800*480;i++)
{
temp[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16;
}
//解决上下颠倒 把一维数组 二维化思考
for(i=0;i<480;i++)
{
for(j=0;j<800;j++)
{
lcd[(480-1-i)*800+j]=temp[i*800+j];
}
}
//解除映射
munmap(lcd,800*480*4);
//6.关闭文件
close(bmp_fd);
close(fd);
}
//显示任意大小图片
int show_anybmp(const char *bmpname)
{
//1.打开屏幕
int fd=0; //接受open的返回值
fd=open("/dev/fb0", O_RDWR);
if(fd==-1) //做错误判断
{
perror("open fb0 fail");
}
//建立屏幕映射
unsigned int* lcd = mmap(NULL, 800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
//打开图片
int bmp_fd=0; //接受open的返回值
bmp_fd=open(bmpname, O_RDWR);
if(bmp_fd==-1) //做错误判断
{
perror("open func.bmp fail");
}
//2.偏移54字节
//先提取到宽
lseek(bmp_fd,18,SEEK_SET);
int w=0;
read(bmp_fd,&w,4);
//printf("w=%d\n",w);//打印宽度信息
//再提取高
lseek(bmp_fd,22,SEEK_SET);
int h=0;
read(bmp_fd,&h,4);
//printf("h=%d\n",h);//打印宽度信息
lseek(bmp_fd,54,SEEK_SET);
//3.读取像素数据 800*480
unsigned char bmp[w*h*3];
read(bmp_fd,bmp,sizeof(bmp));
//4.数据处理
/*
bmp[0]--B
bmp[1]--G
bmp[2]--R
bmp[3]--B
....
lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16;
lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16;
lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16;
*/
unsigned int temp[800*480]={0};
int i=0;
int j=0;
for(i=0;i<w*h;i++)
{
temp[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16;
}
//解决上下颠倒 把一维数组 二维化思考
for(i=0;i<h;i++)
{
for(j=0;j<w;j++)
{
lcd[(h-1-i)*800+j]=temp[i*w+j];
}
}
//解除映射
munmap(lcd,800*480*4);
//6.关闭文件
close(bmp_fd);
close(fd);
}
//在指定位置显示图片 x0,y0为起点坐标
int show_anywherebmp(int x0,int y0,const char *bmpname)
{
//1.打开屏幕
int fd=0; //接受open的返回值
fd=open("/dev/fb0", O_RDWR);
if(fd==-1) //做错误判断
{
perror("open fb0 fail");
}
//建立屏幕映射
unsigned int* lcd = mmap(NULL, 800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
//打开图片
int bmp_fd=0; //接受open的返回值
bmp_fd=open(bmpname, O_RDWR);
if(bmp_fd==-1) //做错误判断
{
perror("open func.bmp fail");
}
//2.偏移54字节
//先提取到宽
lseek(bmp_fd,18,SEEK_SET);
int w=0;
read(bmp_fd,&w,4);
printf("w=%d\n",w);//打印宽度信息
//再提取高
lseek(bmp_fd,22,SEEK_SET);
int h=0;
read(bmp_fd,&h,4);
printf("h=%d\n",h);//打印宽度信息
lseek(bmp_fd,54,SEEK_SET);
//3.读取像素数据 800*480
unsigned char bmp[w*h*3];
read(bmp_fd,bmp,sizeof(bmp));
//4.数据处理
/*
bmp[0]--B
bmp[1]--G
bmp[2]--R
bmp[3]--B
....
lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16;
lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16;
lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16;
*/
unsigned int temp[800*480]={0};
int i=0;
int j=0;
for(i=0;i<w*h;i++)
{
temp[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16;
}
//解决上下颠倒 把一维数组 二维化思考
for(i=0;i<h;i++)
{
for(j=0;j<w;j++)
{
lcd[(h-1-i+y0)*800+j+x0]=temp[i*w+j];
}
}
//解除映射
munmap(lcd,800*480*4);
//6.关闭文件
close(bmp_fd);
close(fd);
}
int get_xy(int *x,int *y)
{
int count=0;
//1.打开触摸屏
int tsfd =open("/dev/input/event0",O_RDWR);
if(tsfd == -1)
{
perror("open ts fail");
}
//2.read
struct input_event ts;
while(1)
{
read(tsfd,&ts,sizeof(struct input_event));
//筛选
if(ts.type ==EV_ABS && ts.code==ABS_X )
{
*x=ts.value; //适合蓝底屏幕
//*x= ts.value*800/1024; //适合黑底屏幕
count++;
}
if(ts.type ==EV_ABS && ts.code==ABS_Y )
{
*y=ts.value; //适合蓝底屏幕
//*y= ts.value*480/600; //适合黑底屏幕
count++;
}
if(count == 2)
{
break;
}
}
//关闭触摸屏
close(tsfd);
}
arm-linux-gnueabi-gcc -o touch LCD_drv_touch.c
效果如下:
效果
6.网络编程(TCP通信)
因为我没听课,所以就不知道他做的什么内容了..这部分我确实没学过,本来打算是寒假去学的,刚刚好,他竟然教了。
前面还有一个多线程的实验,因为不难我就不做了,拿gcc编译工具在UBUNTU上跑就行
代码贴出来
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/input.h>
#include <pthread.h>
//int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
//线程任务函数
void *pth_function1(void *arg)
{
while(1)
{
printf("你真帅!!!\n");
sleep(1);//延时一秒
}
}
//主线程
int main()
{
pthread_t thid; //定义线程ID
//创建一个新的线程,默认属性 任务函数 不传参
pthread_create(&thid, NULL, pth_function1, NULL);
while(1)
{
printf("年轻人不讲武德!!!\n");
sleep(1);//延时一秒
}
}
gcc pth.c -o pth -pthread
然后是第一个实验,TCP的客户端与服务端间的通信
ifconfig
需要改这里:
服务端代码:(server.c)
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <linux/input.h>
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//int listen(int sockfd, int backlog);
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//int socket(int domain, int type, int protocol);
int main()
{
//1.创建socket
int skfd=socket(AF_INET ,SOCK_STREAM, 0);
if(skfd == -1)
{
perror("socket fail");
}
else
{
printf("socket ok\n");
}
//2.bind IP和端口号
//定义结构体
struct sockaddr_in seraddr={0};
seraddr.sin_family=AF_INET; //IPV4
seraddr.sin_port= htons(12345);
//端口号 http-80 8080 Telnet--23 范围:0~65535 个人编程的时候建议5位数的端口号
//htons() 把本地转换为网络序 认识大端和小端存储
seraddr.sin_addr.s_addr=htonl(INADDR_ANY);
//htonl() 课后 认识一下 转换为网络序 INADDR_ANY--0.0.0.0--表示自动获取本机IP
int b_ret=bind(skfd, (struct sockaddr*)&seraddr,sizeof(seraddr));
if(b_ret !=0)
{
perror("bind fail");
}
else
{
printf("bind ok\n");
}
//3.listen--等待连接
int l_ret = listen(skfd,3);
if(l_ret!=0)
{
perror("listen fail");
}
else
{
printf("listen ok\n");
}
//4.accept
struct sockaddr_in cliaddr={0}; //为了存储连接的客户端信息
int len=sizeof(cliaddr);
int newskfd=accept(skfd,(struct sockaddr*)&cliaddr, &len);
if(newskfd == -1)
{
perror("accept fail");
return -1;
}
else
{
printf("accept ok\n");
printf("newskfd=%d,client-ip:%s,client-port:%d\n",newskfd,inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));
}
//5.read/write 服务器一直接收
char buf[1024]={0};
while(1)
{
read(newskfd,buf,sizeof(buf)); //读取消息
printf("buf=%s\n",buf); //打印消息
if( strcmp(buf,"exit") == 0) //字符串的判断
{
break; //跳出循环 关闭通信
}
memset(buf,0,sizeof(buf)); //清空数组
}
//6. 关闭通信
close(skfd);
}
客户端代码:(client.c)
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <linux/input.h>
//int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//int listen(int sockfd, int backlog);
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//int socket(int domain, int type, int protocol);
int main()
{
//1.创建socket
int skfd=socket(AF_INET ,SOCK_STREAM, 0);
if(skfd == -1)
{
perror("socket fail");
}
else
{
printf("socket ok\n");
}
//2.发起连接请求 connect
struct sockaddr_in seraddr={0};
seraddr.sin_family=AF_INET; //IPV4
seraddr.sin_port= htons(12345);
//端口号 http-80 8080 Telnet--23 范围:0~65535 个人编程的时候建议5位数的端口号
//htons() 把本地转换为网络序 认识大端和小端存储
seraddr.sin_addr.s_addr=inet_addr( "192.168.42.168"); //服务器的地址
//htonl() 课后 认识一下 转换为网络序 INADDR_ANY--0.0.0.0--表示自动获取本机IP
int c_ret=connect(skfd, (struct sockaddr*)&seraddr,sizeof(seraddr));
if(c_ret!=0)
{
perror("connect fail");
return -1;
}
else
{
printf("connect ok\n");
}
//3.read /write 通信:客户端一直发消息
char buf[1024]={0};
while(1)
{
printf("请输入要发送的消息:\n");
scanf("%s",buf);
write(skfd,buf,strlen(buf)); //发送消息
if(strcmp(buf,"exit")==0) //判断消息为退出关键字
{
break;
}
printf("buf=%s\n",buf);
}
//4.关闭通信
close(skfd);
}
效果如下:
7.网络编程(UDP通信)
直接贴代码了,比较简单,难在理解整个过程,不然代码是没法写的
本机UBUNTUip为192.168.5.11,想要啥设备接收就写哪个设备的ip
服务端(server.c)
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <linux/input.h>
//ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
int main()
{
//1.创建socket
int skfd=socket(AF_INET ,SOCK_DGRAM, 0);
if(skfd == -1)
{
perror("socket fail");
}
else
{
printf("socket ok\n");
printf("skfd=%d\n",skfd);
}
int s_ret=0; //返回值
char buf[512]={0}; //存储读取内容
struct sockaddr_in seraddr={0}; //来自客户端地址
seraddr.sin_family=AF_INET; //IPV4
seraddr.sin_port= htons(12345);
//端口号 http-80 8080 Telnet--23 范围:0~65535 个人编程的时候建议5位数的端口号
//htons() 把本地转换为网络序 认识大端和小端存储
seraddr.sin_addr.s_addr=inet_addr( "192.168.5.11"); //服务器的地址
//htonl() 课后 认识一下 转换为网络序 INADDR_ANY--0.0.0.0--表示自动获取本机IP
socklen_t addrlen=sizeof(seraddr); //地址长度
while(1)
{
printf("请输入发送的消息\n");
scanf("%s",buf);
s_ret=sendto(skfd,buf, strlen(buf),0,(struct sockaddr*)&seraddr, addrlen);
//面试题 strlen 和 sizeof 对比
if(s_ret==-1)
{
perror("sendto fail");
}
if(strcmp(buf,"exit")== 0)
{
break;
}
memset(buf,0,sizeof(buf)); //用完之后清空
}
//关闭通信
close(skfd);
}
客户端(client.c)
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <linux/input.h>
//ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
int main()
{
//1.创建socket
int skfd=socket(AF_INET ,SOCK_DGRAM, 0);
if(skfd == -1)
{
perror("socket fail");
}
else
{
printf("socket ok\n");
printf("skfd=%d\n",skfd);
}
//2.bind IP和端口号
//定义结构体
struct sockaddr_in seraddr={0};
seraddr.sin_family=AF_INET; //IPV4
seraddr.sin_port= htons(12345);
//端口号 http-80 8080 Telnet--23 范围:0~65535 个人编程的时候建议5位数的端口号
//htons() 把本地转换为网络序 认识大端和小端存储
seraddr.sin_addr.s_addr=htonl(INADDR_ANY);
//htonl() 课后 认识一下 转换为网络序 INADDR_ANY--0.0.0.0--表示自动获取本机IP
int b_ret=bind(skfd, (struct sockaddr*)&seraddr,sizeof(seraddr));
if(b_ret !=0)
{
perror("bind fail");
}
else
{
printf("bind ok\n");
}
int r_ret=0; //返回值
char buf[512]={0}; //存储读取内容
struct sockaddr_in cliaddr={0}; //来自客户端地址
socklen_t addrlen=sizeof(cliaddr); //地址长度
while(1)
{
//接收消息
r_ret=recvfrom(skfd, buf,sizeof(buf),0,(struct sockaddr*)&cliaddr, &addrlen);
if(r_ret == -1)
{
perror("recvfrom fail");
}
else
{
printf("from %s:%s\n",inet_ntoa(cliaddr.sin_addr),buf);
}
if(strcmp(buf,"exit")==0)//判断消息内容
{
break;
}
memset(buf,0,sizeof(buf)); //用完之后清空
memset(&cliaddr,0,sizeof(cliaddr));
}
//关闭通信
close(skfd);
}
尝试一下开发板和ubuntu通信:
好像不太行