2017-2018-1 20155222 201552228 实验二 固件程序设计

2017-2018-1 20155222 201552228 实验二 固件程序设计

实验内容

实验三-并发程序-1

学习使用Linux命令wc(1)

基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端

客户端传一个文本文件给服务器

服务器返加文本文件中的单词数

上方提交代码

附件提交测试截图,至少要测试附件中的两个文件

实验三-并发程序-2

使用多线程实现wc服务器并使用同步互斥机制保证计数正确

上方提交代码

下方提交测试

对比单线程版本的性能,并分析原因

实验三-并发程序-3

交叉编译多线程版本服务器并部署到实验箱中

PC机作客户端测试wc服务器

提交测试截图

实验要求

  • 提交实验报告博客,一组写一篇,实验中贡献小的写博客,贡献多的可以给出同组同学的博客链接。
  • 博客标题:2017-2018-1 学号1 学号2 实验三 实时系统
  • 实验目的,实验步骤
  • 实验中的问题及解决过程
  • 新学到的知识点

实验步骤

Linux系统中的wc(Word Count)命令

功能为统计指定文件中的字节数、字数、行数,并将统计结果显示输出。

  1. 命令格式:
wc [选项]文件...
  1. 命令功能:统计指定文件中的字节数、字数、行数,并将统计结果显示输出。该命令统计指定文件中的字节数、字数、行数。如果没有给出文件名,则从标准输入读取。wc同时也给出所指定文件的总统计数。
  2. 命令参数
  • -c 统计字节数。
  • -l 统计行数。
  • -m 统计字符数。这个标志不能与 -c 标志一起使用。
  • -w 统计字数。一个字被定义为由空白、跳格或换行字符分隔的字符串。
  • -L 打印最长行的长度。
  • -help 显示帮助信息
  • --version 显示版本信息

字数统计函数

int getnumberofwords(char readfile[63335])
//函数返回readfile字符串中的字数
{

    int i,n=0,flag=1;

    for(i = 0; readfile[i]; i ++)//字符串不为空就继续循环

    {

        if(flag == 1)//如果上个字符不是空格

        {

            if(readfile[i] != ‘ ‘)//如果这个字符为空格

            {

                n++;//字数统计加1

                flag = 0;

            }

        }
        else if(readfile[i] == ‘ ‘)
        //如果上个字符是空格而且这个字符也是空格

            flag = 1;

    }

    return n;//返回字符个数

}

文件读写函数

void readfile (char *readfile,char address[1024])
//将address的内容作为地址打开文件读取到readfile中

{

    FILE *fp;

    char ch;

    int i,count;

    if((fp=fopen(address,"rb"))==NULL)//文件打开

    {

        printf("failed to open file!\n");//文件打开失败

        exit(0);

    }

    count=0;

    while((ch=fgetc(fp))!=EOF && count<1024)//读取文件内容

    {

        if(isprint(ch))

        {

            readfile[count]=ch;

            count++;

        }

    }

    fclose(fp);//关闭文件

    return 0;

}

Socket编程基本框架(服务器)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Winsock2.h>
#define MY_PORT 3434

int main()
{
    char *buffer1="connect to server successful!";
    char buffer2[1024]="no client connected to server!";
    char buffer3[1024]="\0";
    char buffer4[1024]="\0";
    int bytes_recvd;
    int m,n;
    m=1;
//打开服务
    WSADATA wsaData;
    WSAStartup(MAKEWORD(1,1),&wsaData);
//初始化
    struct sockaddr_in my_addr;
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(MY_PORT);//htons:将主机的无符号短整型数字节顺序转换成网络字节顺序
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);//htonl:将主机的无符合长整型数字节顺序转换成网络字节顺序。
//指定协议
    SOCKET listen_sock, new_sock;
    listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    //根据指定的地址族、数据类型和协议来生成一个套接字的描述字(listen_sock )
    //地址描述:AP_INET,指定socket类型:SOCK_STREAM,函数返回值为整型socket描述符。
    bind(listen_sock, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));//将一个套接字和一个本地地址与绑定在一起
    //listen_sock:socket描述符,(struct sockaddr *)&my_addr:指向sockaddr类型的指针
    listen(listen_sock, 5);
    //5:在请求队列中允许的最大请求数为5
//定义监听套接字
    new_sock = accept(listen_sock, NULL, NULL);
    //listen_sock:被监听的socket描述符
//发送数据
    send(new_sock, buffer1, strlen(buffer1), 0);
    //new_sock:用于传输数据的socket描述符,buffer:是一个指向要发送数据的指针,strlen(buffer):以字节为单位的数据的长度。
//文件接收
    bytes_recvd = recv(new_sock, buffer2, sizeof(buffer2), 0);
    printf("Server received message(%d bytes): %s\n", bytes_recvd, buffer2);

    memset(buffer3, 0, sizeof(buffer3));
    bytes_recvd = recv(new_sock, buffer3, sizeof(buffer3), 0);
    printf("client:%s\n",buffer3);

    memset(buffer4, 0, sizeof(buffer4));
    printf("server:");
    gets(buffer4);
    send(new_sock, buffer4, strlen(buffer4), 0);

    printf("server disconnected to client successful!");
//关闭套接字
    closesocket(new_sock);
    closesocket(listen_sock);

    WSACleanup();

    while(1)
    {

    }

    return 0;
}

服务器和客户端代码

//服务器

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#define MY_PORT 155228

int readfilewords(char readfile[65536]);

int getnumberofwords(char readfile[63335]);

void main()

{

    char *buffer1="connect to server successful!";

    char buffer2[1024]="no client connected to server!";

    char buffer3[65536]="\0";

    char buffer4[1024]="\0";

    int bytes_recvd;

    int m,n;

    //WSADATA wsaData;

    //WSAStartup(MAKEWORD(1,1),&wsaData);

    struct sockaddr_in my_addr;

    my_addr.sin_family = AF_INET;

    my_addr.sin_port = htons(MY_PORT);//htons:将主机的无符号短整型数字节顺序转换成网络字节顺序

    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);//htonl:将主机的无符合长整型数字节顺序转换成网络字节顺序。

    int listen_sock, new_sock;

    listen_sock = socket(AF_INET, SOCK_STREAM, 0);

    //根据指定的地址族、数据类型和协议来生成一个套接字的描述字(listen_sock )

    //地址描述:AP_INET,指定socket类型:SOCK_STREAM,函数返回值为整型socket描述符。

    bind(listen_sock, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));//将一个套接字和一个本地地址与绑定在一起

    //listen_sock:socket描述符,(struct sockaddr *)&my_addr:指向sockaddr类型的指针

    listen(listen_sock, 5);

    //5:在请求队列中允许的最大请求数为5

    while(1)

    {

        new_sock = accept(listen_sock, NULL, NULL);

        //listen_sock:被监听的socket描述符

        send(new_sock, buffer1, strlen(buffer1), 0);

        //new_sock:用于传输数据的socket描述符,buffer:是一个指向要发送数据的指针,strlen(buffer):以字节为单位的数据的长度。

        bytes_recvd = recv(new_sock, buffer2, sizeof(buffer2), 0);

        printf("Server received message(%d bytes): %s\n", bytes_recvd, buffer2);

        memset(buffer3, 0, sizeof(buffer3));

        bytes_recvd = recv(new_sock, buffer3, sizeof(buffer3), 0);

        m=getnumberofwords(buffer3);

        memset(buffer4, 0, sizeof(buffer4));

        sprintf(buffer4,"%d",m);

        send(new_sock, buffer4, strlen(buffer4), 0);

    }

close(new_sock);

close(listen_sock);

//WSACleanup();

}

int getnumberofwords(char readfile[65536])

{

    int i,n=0,flag=1;

    for(i = 0; readfile[i]; i ++)

    {

        if(flag == 1)

        {

            if(readfile[i] != ‘ ‘)

            {

                n++;

                flag = 0;

            }

        }

        else if(readfile[i] == ‘ ‘)

            flag = 1;

    }

    return n;

}

//客户端
#include <sys/types.h>  

#include <sys/socket.h>  

#include <netinet/in.h>  

#include <arpa/inet.h>  

#include <stdio.h>

#include <stdlib.h>

#define MY_PORT 155228

void readfile (char readfile[65536]);

int main() {

    char buffer1[1024]="connect to server failed!";

    char *buffer2;

    char buffer3[65536]="\0";

    char buffer4[1024]="\0";

    int n;

    int bytes_recvd;

    //WSADATA wsaData;

    //WSAStartup(MAKEWORD(1,1),&wsaData);

    struct sockaddr_in remote_addr;

    remote_addr.sin_family = AF_INET;

    remote_addr.sin_port = htons(MY_PORT);

    remote_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    int conn_sock,new_sock;

    conn_sock = socket(AF_INET, SOCK_STREAM, 0);

    connect(conn_sock, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr));

     bytes_recvd = recv(conn_sock, buffer1, sizeof(buffer1), 0);

     printf("Client received message(%d bytes): %s\n", bytes_recvd, buffer1);

     buffer2="client connected to server successful!";

     send(conn_sock, buffer2, strlen(buffer2), 0);

     //conn_sock:用于传输数据的socket描述符,buffer:是一个指向要发送数据的指针,strlen(buffer):以字节为单位的数据的长度。

         memset(buffer3, 0, sizeof(buffer3));

         readfile(buffer3);

         //printf("client:");

         //gets(buffer3);

         send(conn_sock, buffer3, strlen(buffer3), 0);

         memset(buffer4, 0, sizeof(buffer4));

         bytes_recvd = recv(conn_sock, buffer4, sizeof(buffer4), 0);

         printf("number of words:%s\n", buffer4);

    close(new_sock);

    close(conn_sock);

    //WSACleanup();

    return 0;

}

void readfile (char readfile[65536])

{

    FILE *fp;

    char ch;

    int i,count;

    if((fp=fopen("/home/besti20155228/20155228代码备份/1114exp3/test1.txt","rb"))==NULL)

    {

        printf("failed to open file!\n");

        exit(0);

    }

    count=0;

    while((ch=fgetc(fp))!=EOF && count<1024)

    {

        if(isprint(ch))

        {

            readfile[count]=ch;

            count++;

        }

    }

    fclose(fp);

    return 0;

}

运行结果截图

多线程同步互斥机制

  • 在主线程中初始化锁为解锁状态
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
  • 在编译时初始化锁为解锁状态
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//锁初始化 
  • 访问对象时的加锁操作与解锁操作
pthread_mutex_lock(&mutex)//加锁

pthread_mutex_unlock(&mutex)//释放锁

锁保护的并不是共享变量(或者说是共享内存),对于共享的内存而言,用户是无法直接对其保护的,因为那是物理内存,无法阻止其他程序的代码访问。事实上,锁之所以对关键区域进行了保护,是因为所有线程都遵循了一个规则,那就是在进入关键区域钱加同一把锁,在退出关键区域钱释放同一把锁

加锁是会带来额外的开销的,加锁的代码其运行速度,明显比不加锁的要慢一些,所以,在使用锁的时候,要合理,在不需要对关键区域进行保护的场景下,不要画蛇添足,为其加锁了

信号量

锁有一个很明显的缺点,那就是它只有两种状态:锁定与不锁定。

信号量本质上是一个非负数的整数计数器,它也被用来控制对公共资源的访问。当公共资源增加的时候,调用信号量增加函数sem_post()对其进行增加,当公共资源减少的时候,调用函数sem_wait()来减少信号量。其实是可以把锁当作一个0-1信号量的。

它们是在/usr/include/semaphore.h中进行定义的,信号量的数据结构为sem_t, 本质上,它是一个long型整数

在使用semaphore之前,我们需要先引入头文件#include <semaphore.h>

初始化信号量: int sem_init(sem_t *sem, int pshared, unsigned int value);

成功返回0,失败返回-1

参数

  • sem:指向信号量结构的一个指针
  • pshared: 不是0的时候,该信号量在进程间共享,否则只能为当前进程的所有线程们共享
  • value:信号量的初始值
  • 信号量减1操作,当sem=0的时候该函数会堵塞 int sem_wait(sem_t *sem);

    成功返回0,失败返回-1

参数

  • sem:指向信号量的一个指针

    信号量加1操作 int sem_post(sem_t *sem);

    参数与返回同上

    销毁信号量 int sem_destroy(sem_t *sem);

    参数与返回同上


#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

#define MAXSIZE 10

int stack[MAXSIZE];
int size = 0;
sem_t sem;

// 生产者
void provide_data(void) {
    int i;
    for (i=0; i< MAXSIZE; i++) {
        stack[i] = i;
        sem_post(&sem); //为信号量加1
    }
}

// 消费者
void handle_data(void) {
    int i;
    while((i = size++) < MAXSIZE) {
        sem_wait(&sem);
        printf("乘法: %d X %d = %d\n", stack[i], stack[i], stack[i]*stack[i]);
        sleep(1);
    }
}

int main(void) {

    pthread_t provider, handler;

    sem_init(&sem, 0, 0); //信号量初始化
    pthread_create(&provider, NULL, (void *)handle_data, NULL);
    pthread_create(&handler, NULL, (void *)provide_data, NULL);
    pthread_join(provider, NULL);
    pthread_join(handler, NULL);
    sem_destroy(&sem); //销毁信号量

    return 0;
}

多线程服务器代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>  

#define PORT 5228
#define BACKLOG 5
#define MAXDATASIZE 1000  

void process_cli(int connfd, struct sockaddr_in client);
void *function(void* arg);
struct ARG {
int connfd;
struct sockaddr_in client;
}; 

main()
{
int listenfd,connfd;
pthread_t  tid;
struct ARG *arg;
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t  len;  

if ((listenfd =socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Creatingsocket failed.");
exit(1);
}  

int opt =SO_REUSEADDR;
setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));  

bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(PORT);
server.sin_addr.s_addr= htonl (INADDR_ANY);
if (bind(listenfd,(struct sockaddr *)&server, sizeof(server)) == -1) {
perror("Bind()error.");
exit(1);
}  

if(listen(listenfd,BACKLOG)== -1){
perror("listen()error\n");
exit(1);
}  

len=sizeof(client);
while(1)
{
if ((connfd =accept(listenfd,(struct sockaddr *)&client,&len))==-1) {
perror("accept() error\n");
exit(1);
}
arg = (struct ARG *)malloc(sizeof(struct ARG));
arg->connfd =connfd;
memcpy((void*)&arg->client, &client, sizeof(client));  

if(pthread_create(&tid, NULL, function, (void*)arg)) {
perror("Pthread_create() error");
exit(1);
}
}
close(listenfd);
}  

void process_cli(int connfd, struct sockaddr_in client)
{
int num;
char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];  

printf("Yougot a connection from %s. \n ",inet_ntoa(client.sin_addr) );
num = recv(connfd,cli_name, MAXDATASIZE,0);
if (num == 0) {
close(connfd);
printf("Clientdisconnected.\n");
return;
}
cli_name[num - 1] =‘\0‘;
printf("Client‘sname is %s.\n",cli_name);  

while (num =recv(connfd, recvbuf, MAXDATASIZE,0)) {
recvbuf[num] =‘\0‘;
printf("Receivedclient( %s ) message: %s",cli_name, recvbuf);
int i;
for (i = 0; i <num - 1; i++) {
if((recvbuf[i]>=‘a‘&&recvbuf[i]<=‘z‘)||(recvbuf[i]>=‘A‘&&recvbuf[i]<=‘Z‘))
{
recvbuf[i]=recvbuf[i]+ 3;
if((recvbuf[i]>‘Z‘&&recvbuf[i]<=‘Z‘+3)||(recvbuf[i]>‘z‘))
recvbuf[i]=recvbuf[i]- 26;
}
sendbuf[i] =recvbuf[i];
}
sendbuf[num -1] = ‘\0‘;
send(connfd,sendbuf,strlen(sendbuf),0);
}
close(connfd);
}  

void *function(void* arg)
{
struct ARG *info;
info = (struct ARG*)arg;
process_cli(info->connfd,info->client);
free (arg);
pthread_exit(NULL);
}  

运行结果截图

参考资料

linux中wc命令用法

C语言统计单词个数

Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)

时间: 2024-12-10 13:31:28

2017-2018-1 20155222 201552228 实验二 固件程序设计的相关文章

2018-2019-1 20165201 20165203 20165206 实验二 固件程序设计

- 2018-2019-1 20165201 20165203 20165206 实验二 固件程序设计 - 任务一 固件程序设计-1-MDK - 任务要求 0. 注意不经老师允许不准烧写自己修改的代码 1. 三人一组 2. 参考云班课资源中"信息安全系统实验箱指导书.pdf "第一章,1.1-1.5安装MDK,JLink驱动,注意,要用系统管理员身分运行uVision4,破解MDK(破解程序中target一定选ARM) 3. 提交破解程序中产生LIC的截图 4. 提交破解成功的截图 -

2018-2019-1 20165308 20165317 20165331 实验二 固件程序设计

2018-2019-1 20165308 20165317 20165331 实验二 固件程序设计 成员 20165308张士洋 20165317宁心宇 20165331胡麟 实验二 固件程序设计-1-MDK 0. 注意不经老师允许不准烧写自己修改的代码 1. 三人一组 2. 参考云班课资源中"信息安全系统实验箱指导书.pdf "第一章,1.1-1.5安装MDK,JLink驱动,注意,要用系统管理员身分运行uVision4,破解MDK(破解程序中target一定选ARM) 3. 提交破

2018-2019-1 20165227 20165228 20165237 实验二 固件程序设计

2018-2019-1 20165227 20165228 20165237 实验二 固件程序设计 实验步骤 任务一:固件程序设计-1-MDK 要求: 0.注意不经老师允许不准烧写自己修改的代码 1.三人一组 2.参考云班课资源中"信息安全系统实验箱指导书.pdf "第一章,1.1-1.5安装MDK,ULink驱动 注意:要用系统管理员身分运行uVision4,破解MDK(破解程序中target一定选ARM) 3.提交破解程序中产生LIC的截图 4.提交破解成功的截图 实验步骤截图:

2019-2020-1 20175312 20175321 20175333 实验二 固件程序设计

2019-2020-1 20175312 20175321 20175333 实验二 固件程序设计 本小组成员 20175312 20175321 20175333 实验二 固件程序设计-1-MDK 0. 注意不经老师允许不准烧写自己修改的代码 1. 三人一组 2. 参考云班课资源中"信息安全系统实验箱指导书.pdf "第一章,1.1-1.5安装MDK,JLink驱动,注意,要用系统管理员身分运行uVision4,破解MDK(破解程序中target一定选ARM) 3. 提交破解程序中产

2019-2020-1 20175334 20175322 20175315 实验二 固件程序设计

我们组陈煜扬同学的博客: 实验二 固件程序设计 补充截图: 原文地址:https://www.cnblogs.com/lxr1006/p/11877739.html

2019-2020-2 20175224 20175236 20175325 实验二 固件程序设计

目录 一.实验步骤 二.实验过程中遇到的问题及解决 三.实验感想 一.实验步骤 任务一 MDK 注意不经老师允许不准烧写自己修改的代码 两人(个别三人)一组 参考云班课资源中“信息安全系统实验箱指导书.pdf “第一章,1.1-1.5安装MDK,JLink驱动,注意,要用系统管理员身分运行uVision4,破解MDK(破解程序中target一定选ARM) 提交破解程序中产生LIC的截图 提交破解成功的截图 实验步骤: 找到exp2\软件资料\MDK4.74路径下的mdk474.exe文件,点击并

20145221高其&amp;20145326蔡馨熠《信息安全系统设计基础》实验二 固件设计

20145221高其&20145326蔡馨熠<信息安全系统设计基础>实验二 固件设计 实验目的与要求 了解多线程程序设计的基本原理,学习 pthread 库函数的使用. 了解在 linux 环境下串行程序设计的基本方法. 掌握终端的主要属性及设置方法,熟悉终端I /O 函数的使用.学习使用多线程来完成串口的收发处理. 熟悉linux开发环境,学会基于S3C2410的linux开发环境的配置和使用.使用linux的armv4l-unknown-linux-gcc编译,使用基于NFS方式的

20145317 《信息安全系统设计基础》实验二 固件设计

北京电子科技学院(BESTI) 实     验    报     告 课程: 密码系统设计基础                                                               班级: 1453班 姓名:彭垚                                                                               学号:20145317 成绩:                              

实验二 20155335 实验报告 固件程序设计

实验二 20155307 20155335 20155338 实验报告 固件程序设计 一.实验内容: 1.安装MDK,JLink驱动,运行uVision4,破解MDK2.KEIL-MDK 中添加Z32 SC-000芯片库,完成LED实验3.完成UART发送与中断接收实验4.理解国密算法标准SM1,SM2,SM3,SM4并用gcc和gcc-arm编译5.完成SM1加密实验 二.实验步骤 在开始试验之前,先安装MDK,JLink驱动,运行uVision4,破解MDK, 很多付费软件为了保证试用和购买