linux bluez语音传输,Linux BlueZ PCM 音频播放器

自己写的简单的实验代码,贴上来看看,有兴趣的话,大家可以交流

/******************************************************************************/

/**                                                                                                                           **/

/**                         MODULES USED                                                                  **/

/**                                                                                                                            **/

/******************************************************************************/

#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "msgqueue.h"

/******************************************************************************/

/**                                                                                                                           **/

/**                         DEFINITIONS AND MACROS                                              **/

/**                                                                                                                           **/

/******************************************************************************/

#define DONGLE_ADDR  "00:11:67:58:D1:0F"     /*ISSC*/

#define HEAD_SET_ADDR "83:82:5B:00:A5:A3"     /*NK-808 channel 1*/

#define HEAD_SET_CHAN   1

//#define PCM_DATA_PATH   "/tmp/sco.dat"

//#define PCM_DATA_PATH   "/mnt/heart.pcm"

#define PCM_DATA_PATH   "/mnt/tianhou.pcm"

#define RECV_BUFFER     64

#define SEND_BUFFER     64

typedef pthread_t thread_T;

typedef void *(*pthread_startroutine_t) (void *);

typedef void *pthread_addr_t;

typedef void threadArg_T;

typedef void (*threadFunc_T)(void *);

/*debugging micro*/

#ifdef ENABLE_DEBUG

int DebugEnabled = 0;

#else

#define DebugEnabled    1

#endif

#define DDBG(fmts)  if(DebugEnabled)printf(fmts)

#define DBG(fmts,args) if(DebugEnabled)printf(fmts,args)

#define DBG2(fmts,arg1,arg2) if(DebugEnabled)printf(fmts,arg1,arg2)

/******************************************************************************/

/**                                                                                                                           **/

/**                            TYPEDEF AND STRUCTURE                                          **/

/**                                                                                                                            **/

/******************************************************************************/

struct _dongle_priv {

int hci_sock;

int sco_sock;

int device_channel;

char ag_addr[20];  /* adddress of adapter */

char hs_addr[20];

unsigned char isServiceConnected;

char isScoConnected;

char isRunning;

char callSetup;

char callAccept;

};

typedef struct _dongle_priv bt_data;

/******************************************************************************/

/**                                                                                                                           **/

/**                            GLOBAL VARIABLES                                                         **/

/**                                                                                                                            **/

/******************************************************************************/

bt_data * BTd;

static sem_t   Sem;

/******************************************************************************/

/**                                                                                                                           **/

/**                         LOCAL FUNCTIONS                                                             **/

/**                                                                                                                            **/

/******************************************************************************/

thread_T thread_create(int priority, threadFunc_T startFunc, threadArg_T *arg)

{

thread_T             thread;

pthread_attr_t       thread_attr;

struct sched_param   param;

pthread_attr_init(&thread_attr);

/* pthread_attr_setinheritsched(PTHREAD_EXPLICT_SCHED); */

pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);

param.sched_priority = priority;

pthread_attr_setschedparam(&thread_attr, &param);

pthread_create(&thread, &thread_attr, (pthread_startroutine_t)startFunc,

(pthread_addr_t)arg);

return(thread);

}

void set_bit(int offset)

{

BTd->isServiceConnected |= (0x01

static int rfcomm_connect(bdaddr_t * src, bdaddr_t * dst, uint8_t channel)

{

struct sockaddr_rc addr;

int s;

if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {

return -1;

}

memset(&addr, 0, sizeof(addr));

addr.rc_family = AF_BLUETOOTH;

bacpy(&addr.rc_bdaddr, src);

addr.rc_channel = 0;

if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {

printf("rfcomm bind error\n");

close(s);

return -1;

}

memset(&addr, 0, sizeof(addr));

addr.rc_family = AF_BLUETOOTH;

bacpy(&addr.rc_bdaddr, dst);

addr.rc_channel = channel;

if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {

printf("rfcomm connect error\n");

close(s);

return -1;

} else{

printf("connecting successfully sock %d\n",s);

}

return s;

}

static int sco_connect(bdaddr_t *src, bdaddr_t *dst)

{

struct sockaddr_sco addr;

//struct sco_conninfo conn;

//struct sco_options opts;

int s;

if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {

return -1;

}

memset(&addr, 0, sizeof(addr));

addr.sco_family = AF_BLUETOOTH;

bacpy(&addr.sco_bdaddr, src);

if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {

close(s);

return -1;

}

memset(&addr, 0, sizeof(addr));

addr.sco_family = AF_BLUETOOTH;

bacpy(&addr.sco_bdaddr, dst);

if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 ){

close(s);

printf("sco connecting failed\n");

return -1;

}

return s;

}

static int start_rfcomm_link(char *dst , char *src , int channel)

{

bdaddr_t usb_dongle_addr,head_set_addr;

int fd;

if (!dst||!src){

return -1;

}

str2ba(src,&usb_dongle_addr);

str2ba(dst,&head_set_addr);

fd = rfcomm_connect(&usb_dongle_addr,&head_set_addr,channel);

return fd;

}

static int start_sco_link(char *dst , char *src)

{

bdaddr_t usb_dongle_addr,head_set_addr;

int fd;

//uint16_t sco_handle, sco_mtu;

if (!dst||!src){

return -1;

}

str2ba(src,&usb_dongle_addr);

str2ba(dst,&head_set_addr);

fd = sco_connect(&usb_dongle_addr,&head_set_addr);

return fd;

}

static int cind_cmd_str(char *cmd)

{

if (!cmd){

return -1;

}

memset(cmd,0,sizeof(cmd));

strcpy(cmd,"\r\n+CIND:(\"service\",(0,1)),(\"call\",(0,1)),(\"callsetup\",(0,3)),(\"signal\",(0-5)),(\"roam\",(0-1))\r\n");

return 0;

}

static int at_rx(int fd_at, char *receive)

{

int retval,ret;

fd_set rfds;

struct timeval tv;

FD_ZERO(&rfds);

FD_SET(fd_at, &rfds);

tv.tv_sec = 0;

tv.tv_usec = 5000;

if (!receive){

return -1;

}

memset(receive,0,sizeof(receive));

if ((retval = select(fd_at+1, &rfds, NULL, NULL, &tv)) > 0){

memset(receive,0,RECV_BUFFER);

ret = read(fd_at,receive,RECV_BUFFER);

if (ret > 0){

DBG("recving from headset %s\n",receive);

} else if (-1 == ret){

close(fd_at);

BTd->isRunning = 0;

}

} else if (!retval){

//DDBG("time out\n");

}

return 0;

}

static int at_tx(int fd_at,char* send)

{

if (strlen(send)){

DBG("AG Sending %s\n",send);

write(fd_at,send,strlen(send));

}

return 0;

}

static int at_txrx(int fd_at,char* send, char *receive)

{

int ret = 0;

fd_set rfds;

struct timeval tv;

int retval;

FD_ZERO(&rfds);

FD_SET(fd_at, &rfds);

tv.tv_sec = 3;

tv.tv_usec = 0;

memset(receive,0,sizeof(receive));

if (strlen(send)){

DBG("AG Sending %s\n",send);

write(fd_at,send,strlen(send));

}

if ((retval = select(fd_at+1, &rfds, NULL, NULL, &tv)) > 0){

memset(receive,0,RECV_BUFFER);

ret = read(fd_at,receive,RECV_BUFFER);

if (ret){

DBG("[at_rxtx]recving from headset %s\n",receive);

}

} else if (!retval){

//DDBG("time out\n");

}

return 0;

}

static void monitor_headset(int fd_rfcomm)

{

char recv_buf[RECV_BUFFER] = {0};

char send_buf[SEND_BUFFER] = {0};

while (1 == BTd->isRunning){

at_rx(fd_rfcomm, recv_buf);

if (strstr(recv_buf,"AT+BRSF")){

at_tx(fd_rfcomm,"\r\n+BRSF:49\r");

at_tx(fd_rfcomm,"\r\nOK\r\n");

set_bit(0);

continue;

}

if (strstr(recv_buf,"AT+CIND=?")){

cind_cmd_str(send_buf);

at_tx(fd_rfcomm,send_buf);

at_tx(fd_rfcomm,"\r\nOK\r\n");

set_bit(1);

continue;

}

if (strstr(recv_buf,"AT+CIND")){

at_tx(fd_rfcomm,"\r\n+CIND:1,0,0,2,0\r\n");

at_tx(fd_rfcomm,"\r\nOK\r\n");

set_bit(2);

continue;

}

if (strstr(recv_buf,"AT+CMER")){

at_tx(fd_rfcomm,"\r\nOK\r\n");

set_bit(3);

continue;

}

//Standard call hold and multiparty handling AT command

if (strstr(recv_buf,"AT+CHLD")){

at_tx(fd_rfcomm,"\r\n+CHLD:0\r\n");

at_tx(fd_rfcomm,"\r\nOK\r\n");

set_bit(4);

continue;

}

//Standard “Call Waiting notification” AT command

if (strstr(recv_buf,"AT+CCWA")){

at_tx(fd_rfcomm,"\r\nOK\r\n");

set_bit(5);

continue;

}

//volume setting

if (strstr(recv_buf,"AT+VGS")){

at_tx(fd_rfcomm,"\r\nOK\r\n");

set_bit(6);

continue;

}

//volume setting

if (strstr(recv_buf,"AT+VGM")){

at_tx(fd_rfcomm,"\r\nOK\r\n");

set_bit(7);

continue;

}

if (strstr(recv_buf,"ATA")){

//CallingAccept = 1;

BTd->callAccept = 1;

DDBG("ATA is received\n");

at_tx(fd_rfcomm,"\r\nOK\r\n");

at_tx(fd_rfcomm,"\r\n+CIEV=2,1\r\n");

continue;

}

}

}

static void audio_loop(int fd_sco)

{

char recv_buf[RECV_BUFFER] = {0};

int retval,ret;

fd_set rfds;

struct timeval tv;

FD_ZERO(&rfds);

FD_SET(fd_sco, &rfds);

tv.tv_sec = 3;

tv.tv_usec = 0;

memset(recv_buf,0,RECV_BUFFER);

if ((retval = select(fd_sco+1, &rfds, NULL, NULL, &tv)) > 0){

ret = read(fd_sco,recv_buf,1023);

if (ret){

//DBG("recving from headset %s\n",receive);

//DBG("recv_length %d\n",ret);

//DBG("%x\n",recv_buf);

}

write(fd_sco,recv_buf,ret);

} else if (!retval){

//DDBG("time out\n");

}

}

static int get_file_size(char *file_path)

{

FILE * fd;

int start,end,fileLen;

fd = fopen(file_path,"r");

if (fd){

fseek(fd, 0, SEEK_SET);

start = ftell(fd);

fseek(fd, 0, SEEK_END);

end = ftell(fd);

fileLen = end - start + 1;

/*move to the head*/

fseek(fd, 0, SEEK_SET);

DBG("audio fileLength %d\n",fileLen);

fclose(fd);

return fileLen;

} else{

return -1;

}

}

static unsigned char * fill_pcm_buffer(char * pcm_file_path,int *length)

{

int size = 0;

FILE *fd;

unsigned char * pcmDataPtr;

if (!pcm_file_path){

return NULL;

}

size = get_file_size(pcm_file_path);

if (size > 0){

*length = size;

pcmDataPtr = (unsigned char *)malloc(size);

if (!pcmDataPtr){

DDBG("can't allocate memory\n");

return NULL;

}

memset(pcmDataPtr,0,size);

fd = fopen(pcm_file_path,"r");

if (!fd){

return NULL;

}

fread(pcmDataPtr,1,size,fd);

fclose(fd);

return pcmDataPtr;

} else{

return NULL;

}

}

static bt_data * init_bt_para()

{

bt_data * btd;

btd = (bt_data *)malloc(sizeof(bt_data));

if (!btd){

printf("opps can't allocate resource!\n");

exit(-1);

}

memset(btd,0,sizeof(*btd));

strcpy(btd->ag_addr,DONGLE_ADDR);

strcpy(btd->hs_addr,HEAD_SET_ADDR);

btd->device_channel = HEAD_SET_CHAN;

btd->callSetup = 0;

btd->callAccept = 0;

btd->isRunning = 0;

btd->isServiceConnected = 0;

btd->isScoConnected = 0;

btd->hci_sock = -1;

btd->sco_sock = -1;

return btd;

}

static int ring_headset(int fd_rfcomm)

{

char recv_buf[RECV_BUFFER] = {0};

sem_wait(&Sem);

at_txrx(fd_rfcomm,"\r\nRING\r\n",recv_buf);

while (!strstr(recv_buf,"ATA")&&!BTd->callAccept){

at_txrx(fd_rfcomm,"\r\nRING\r\n",recv_buf);

}

at_tx(fd_rfcomm,"\r\nOK\r\n");

at_tx(fd_rfcomm,"\r\n+CIEV:2,1\r\n");

sem_destroy(&Sem);

return 0;

}

static void play_pcm_audio(int fd_sco,unsigned char * pcm_buffer,int max_length,int times)

{

#define OFFSET  48

int i;

int cur = 0;

int retval;

unsigned char *pdata;

unsigned char buffer[64];

fd_set rfds,wfds;

struct timeval tv;

unsigned int sector = 300*1024;

if (!pcm_buffer){

return -1;

}

FD_ZERO(&rfds);

FD_SET(fd_sco, &rfds);

FD_ZERO(&wfds);

FD_SET(fd_sco, &wfds);

tv.tv_sec = 0;

tv.tv_usec =8000;

pdata = pcm_buffer;

for (i = 0 ; i < times ; i++){

while (cur < max_length){

if ((retval = select(fd_sco+1, NULL, &wfds, NULL, &tv)) > 0){

//fread(receive,1,OFFSET,fd_music);

//memset(buffer,0,sizeof(buffer));

//memcpy(buffer,pdata,OFFSET);

printf("twins\r\n");

//printf("twins\r\n");

//usleep(1);

//printf("\r\n");

write(fd_sco,pdata,48);

cur += OFFSET;

pdata += OFFSET;

if (cur > sector){

sleep(5);

sector += 300*1024;

}

}

}

printf("music data is finished\n");

sleep(2);

pdata = pcm_buffer;

cur = 0;

sector = 300*1024;

}

//close(fd_sco);

free(pcm_buffer);

printf("audio transfer over\n");

return;

}

void init_hcid_conf()

{

system("hcid -f /etc/bluetooth/hcid.conf");

}

int main()

{

int fd_rfcomm,fd_sco;

unsigned char * pcm_buffer;

int max_length;

bt_data *btd;

init_hcid_conf();

btd = init_bt_para();

BTd = btd;

fd_rfcomm = start_rfcomm_link(btd->hs_addr, btd->ag_addr, btd->device_channel);

if (fd_rfcomm < 0){

exit(-1);

}

btd->isRunning = 1;

btd->hci_sock = fd_rfcomm;

thread_create(50, (threadFunc_T)monitor_headset, (threadArg_T *)btd->hci_sock);

thread_create(50, (threadFunc_T)ring_headset, (threadArg_T *)btd->hci_sock);

pcm_buffer = fill_pcm_buffer(PCM_DATA_PATH, &max_length);

while (1){

if (btd->isServiceConnected == 0xff&&!btd->callSetup){

//printf("service level connection finished\n");

//ready to make/accept a call

at_tx(fd_rfcomm,"\r\n+CIEV=3,1\r\n");

sem_post(&Sem);

//CallSetup = 1;

btd->callSetup = 1;

}

if (0 == btd->isScoConnected){

fd_sco = start_sco_link(btd->hs_addr,btd->ag_addr);

}

if (fd_sco > 0){

//printf("sco link successfully!\n");

btd->sco_sock = fd_sco;

btd->isScoConnected = 1;

}

if (btd->callAccept == 1){

play_pcm_audio(btd->sco_sock, pcm_buffer, max_length,1);

break;

}

}

//sleep(80);

close(btd->sco_sock);

close(btd->hci_sock);

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/528011.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

光纤收发器的原理及应用_光纤收发器的工作原理及使用方法介绍

关于光纤收发器的工作原理以及使用方法这块&#xff0c;在这里飞畅科技的小编做了专门的整理&#xff0c;首先&#xff0c;我们来了解下什么是光纤收发器&#xff0c;光纤收发器是一种将短距离的双绞线电信号和长距离的光信号进行互换的以太网传输媒体转换单元&#xff0c;在很…

变频器按启动没反应_ABB变频器启动无反应维修那些事

[标题]常州凌科自动化是电路板芯片级维修服务商&#xff0c;有健全的维修中心&#xff0c;致力于各类复杂工控电气设备修复工作。我们有十年变频器维修经验的技术工程师、安装人员组成的强大技术队伍&#xff1b;充分利用自己己有的人才、测试设备、试验平台、为企业提供先进、…

C语言编程序1到100的素数,c语言输出100以内素数 c语言编程输出1到100之间素数并求和,在线等,急?...

C语言&#xff0c;编写函数判断一个整数是否为素数&#xff0c;在主函数中调用该函数并输出100以内的全部素数&#xff1f;参考代码&#xff1a;#include &ltstdio.h&gtint is_prime_number(int n){int iint result 1if(n1)return 0for(i2i&ltni ){if(n%i0){resul…

用jsonserve和axios做交互_详解解决使用axios发送json后台接收不到的问题

问题描述按照axios官网例子发起请求传递json&#xff0c;后台接受到的数据为空&#xff0c;一直卡在options阶段。尝试的方法开始以为是接口有问题&#xff0c;使用postman测试下&#xff0c;一切正常&#xff0c;百思不得其解&#xff0c;看了好多issue也解决不了&#xff0c;…

2020国开c语言程序设计1075,代号1253国开点大2017年6月春季学期本科期末考试《C语言程序设计》试题及答案.pdf...

试卷代号:1253座位号rn国家开放大学(中央广播电视大学)2017 年春季学期"开放本科"期末考试C 语言程序设计试题2017 年 6 月E自一、单项选择题(把合适的选项编号填写在括号内。每小题 2 分&#xff0c;共28 分)l. C 语言中的选择类语句有两条&#xff0c;它们是( )。A…

c语言内容逆置程序设计,C语言程序设计练习题含程序及参考答案.docx

C语言练习题(所提供的源程序均采用自定义函数方式解决&#xff0c;如不采用函数方式&#xff0c;也可直接在main函数中借鉴该思想编程&#xff0c;因时间有限&#xff0c;所有程序未能一一—验证&#xff0c;仅供参考使用)1定义一个函数intfun(inta,intb,intc)&#xff0c;它的…

一阶系统单位阶跃响应的特点_一阶系统的阶跃响应有什么特点

一、一阶系统  用一阶微分方程描述的系统。二、一阶系统典型的数学模型   三、典型输入响应1。单位阶跃响应  。  y(t)的特点&#xff1a;  (1)由动态分量和稳态分量两部分组成。  (2)是一单调上升的指数曲线。  (3)当tT时&#xff0c;y0。632。(4)曲线的初始斜…

数学式子对应的c语言表达式是,把数学式写成C语言表达式

(1) 3.26*exp(x)1.0/3.0*pow((ab), 4)(2) 2*sqrt(x)(ab)/(3.0*sin(x))(3) g*m1*m2/(r*r)(4) double pi 3.142.0*pi*r pi*r*r cos(45.0*pi / 180.0 )(5) loan * rate * pow( (1rate) , month ) / ( pow( (1rate) , month) - 1)扩展资料&#xff1a;指针&#xff1a;如果一个变…

pandas 每一列相加_Python3 numpy amp; pandas 学习笔记

写在前面在用python做一些ML和DL的工作前&#xff0c;先看莫烦大佬的视频学习一下numpy和pandas这两个数据处理包&#xff0c;学习中记了一些笔记&#xff0c;便于自己日后查阅&#xff0c;同时发布到知乎希望能够帮助到其他小伙伴&#xff01;视频如下&#xff1a;Numpy &…

c语言学生成绩查询系统2018,南昊网上阅卷学生成绩查询系统

2018南昊网上阅卷学生成绩查询系统开放了&#xff0c;这是面向南昊当地的中小学生们的一款优质的查询学习成绩的平台&#xff0c;只要登录自己的账号就能查询自己的成绩排名情况。对于老师来说这也是一款网上阅卷系统&#xff0c;是一个非常幼稚的学习平台。家长也可以登录本平…

python3 批量定义多个变量_Python3 基本数据类型详解

文章来源&#xff1a;加米谷大数据Python 中的变量不需要声明。每个变量在使用前都必须赋值&#xff0c;变量赋值以后该变量才会被创建。在 Python 中&#xff0c;变量就是变量&#xff0c;它没有类型&#xff0c;我们所说的"类型"是变量所指的内存中对象的类型。等号…

控制cpu_I/O控制器及控制方式,了解一下

1、什么是I/O控制器由于CPU无法直接控制I/O设备的机械部件&#xff0c;因此I/O设备还要有个电子部件作为CPU和I/O设备机械部件之间的“中介”&#xff0c;用于实现CPU对设备的控制&#xff0c;这个电子部件就是I/O控制器&#xff0c;又称为设备控制器。I/O控制器是控制计算机输…

图形化c语言编程,「分享」C语言如何编写图形界面

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼贴吧内经常有人问C语言是不是只能用于字符终端界面开发&#xff0c;不能用于图形界面。大家也都有回答&#xff0c;需要其他的库。MFC&#xff0c;GTK&#xff0c;QT。本人近期刚用GTK库加上纯C写成了第一个LINUX实用程序。现在与大…

fpga初始化错误_FPGA低温启动失败

本文来源&#xff1a;https://blog.csdn.net/shanekong/article/details/29923925现象描述在给 medium 板光端机做低温试验时&#xff0c;分别给发送版、接收板断电重新启动&#xff0c;发现有的板子在 -40 可以启动&#xff0c;而有些板子在 -20 都不能启动&#xff0c;需要升…

在C语言中023是八进制数,C语言总结

十一天课的总结(仅仅为总结&#xff0c;具体请看前面的)一、顺序结构从上往下依次运行的代码结构计算机运行程序时&#xff0c;都是编译成二进制文件。计算机中又分为二进制&#xff1a;比如 101001001就是一个二进制数字八进制&#xff1a;比如 023767是一个八进制数字。前面…

机器人最新天赋符文天赋加点图_常德2020中小学机器人竞赛开赛 286名选手现场比拼技能...

尚一网讯(记者 肖志芳 文/图)自己设计机器人&#xff0c;还要操控他们完成各项高难度动作进行竞技对抗&#xff0c;这似乎挺难&#xff0c;但是许多中小学生却对此游刃有余。10月11日&#xff0c;常德市2020年中小学机器人竞赛在武陵区第一小学举行&#xff0c;来自全市143支代…

c语言在函数中只执行一次,请问大家,为什么我调用我定义的函数俩次,但是程序只执行一次...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼#include #include #include void gotoxy(int y,int x){COORD scrn;HANDLE hOuputGetStdHandle(STD_OUTPUT_HANDLE);scrn.Xx;scrn.Yy;SetConsoleCursorPosition(hOuput,scrn);}void put(int n,char ch){for(int i0;iprintf("%…

cmd imp导入dmp文件_这是一篇长篇入门级数据库讲解:oracle数据库数据导入导出步骤...

正如标题一样&#xff0c;本文内容主要介绍了浅谈入门级oracle数据库数据导入导出步骤&#xff0c;文章通过步骤解析介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值&#xff0c;需要的朋友们下面随着小编来一起学习学习吧&#xff01;&#xff01;&…

学校门口的树C语言算法,C语言校园导游程序设计汇报.doc

C语言校园导游程序设计汇报《应用程序设计课程设计》报告班级&#xff1a;学号&#xff1a;姓名&#xff1a;指导教师&#xff1a;成绩评定&#xff1a;目录题目&#xff1a;设计一个校园导游程序&#xff0c;为来访的客人提供各种信息查询服务一.需求分析&#xff1a;此次课程…

linux 使用ssr客户端_【第一期】基于 @vue/cli3 与 koa 创建 ssr 工程

什么是基于同构代码的 SSR 服务(Server-side rendering based on isomorphic code)首先&#xff0c;我们需要先明白什么是 spa (single page application)&#xff0c;以及基于 vue 的 spa 是如何工作的&#xff0c;这里不展开&#xff0c;请参考&#xff1a;单页应用:https://…