头歌Linux系统编程

文章目录

嵌入式Linux应用开发入门

第1关 安装嵌入式开发工具

根据文档安装

第2关 交叉编译工具使用

C语言程序设计编辑与调试环境

第1关 打印输出 Hello World

#include<stdio.h>
	int main(void)
	{  
	/********* Begin *********/
        printf("Hello World");
	/********* End *********/
       return 0;
	}

第2关 打印输出图形

#include<stdio.h>
	int main(void)
	{  	
	/********* Begin *********/
        printf("    *\n");
        printf("   ***\n");
        printf("  OK\n");
        printf(" Hello!\n");
        printf("*********");
	/********* End *********/
       return 0;
	}

第3关 求3个数的最大值

#include<stdio.h>
	int main(void)
	{  
	/********* Begin *********/
        int a,b,c,max;
        scanf("%d,%d,%d",&a,&b,&c);
        if(b>a){
            max=b;
        }
        else{
            max=a;
        }
        if(max<c){
            max=c;
        }
         printf("max=%d",max);
	/********* End *********/
       return 0;
	}


第4关 熟悉C语言调试过程

#include"stdio.h"
int main(void)
  {
	  /********* Begin *********/
      int x;
      int y=2,z=3;
      scanf("%d",&x); 
      if(x==y+z)
          printf("*****");
      else  
          printf("#####");
      return 0;
	  /********* End *********/
  }

Linux之C编程入门

第1关 第一个C程序

vim test.c
#include <stdio.h>
void main(){
        printf("Hello world\n");
}
gcc test.c
./a.out      

第2关 Linux编译C程序

vim test.c
#include <stdio.h>
void main(){
        printf("Hello GCC\n");
}
gcc test.c -o firstExec
./firstExec          

第3关 Linux之静态库编写

vim Add.h
在Add.h中加入以下代码后保存用 :wq
#include <stdio.h>
int Add(int a,int b);

vim Add.c
在Add.c中加入以下代码后保存用 :wq
#include "stdio.h"
int Add(int a,int b){
        return a+b;
}

gcc -c Add.c -o Add.o
ar rcs libAdd.a Add.o

vim main.c
在main.c中加入以下代码后保存用 :wq
#include "Add.h"
int main(){
        int c=Add(10,2);
        return c;
}

gcc main.c -o exe -L ./ -lAdd
./exe


第4关 Linux之动态库编写

vim Sub.h
在Sub.h中加入以下代码后保存用 :wq
#include <stdio.h>
int Sub(int a,int b);

vim Sub.c
在Sub.c中加入以下代码后保存用 :wq
#include "stdio.h"
int Sub(int a,int b){
        return a-b;
}

gcc -fPIC -c Sub.c -o Sub.o
gcc -shared Sub.o -o libSub.so

vim main.c
在main.c中加入以下代码后保存用 :wq
#include <stdio.h>
#include "Sub.h"
int main(){
        int c=Sub(10,2);
        return c;
}

gcc main.c -o exe -L ./ -lSub
./exe

vim /etc/ld.so.conf
加入 /root 保存
ldconfig
./exe

Linux时间编程

第1关 Linux获取时间

#include <stdio.h>
#include <unistd.h>
#include <time.h>
typedef struct _localtimestruct
{
	int year;
	int month;
	int day;
	int hour;
	int minute;
	int second;
}localtimestruct;

time_t gettimesecond (void)
{
	/*************Begin***********/
	return time(NULL);
	/**************End************/
}
void getlocaltv (localtimestruct *ltinfo)
{
	/*************Begin***********/
	struct tm *current;
    time_t now_second;//=time(NULL);
    current=localtime(&now_second);
	ltinfo->year = current->tm_year;
	ltinfo->month = current->tm_mon;
    ltinfo->day = current->tm_mday;
    ltinfo->hour = current->tm_hour;
    ltinfo->minute = current->tm_min;
    ltinfo->second = current->tm_sec;	
	/**************End************/
}

第2关 Linux时间相互转换

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

typedef struct _localtimestruct
{
	int year;
	int month;
	int day;
	int hour;
	int minute;
	int second;
}localtimestruct;
void func (void);
void timetrans (time_t current, char *time_str, localtimestruct *ltinfo, struct tm *tm_time)
{
	/*************Begin***********/
	strcpy(time_str,ctime(&current));
    memcpy(tm_time, gmtime(&current),sizeof(struct tm));
	ltinfo->year = tm_time->tm_year+1900;
    ltinfo->month = tm_time->tm_mon+1;
    ltinfo->day = tm_time->tm_mday;
    ltinfo->hour = tm_time->tm_hour;
    ltinfo->minute = tm_time->tm_min;
    ltinfo->second = tm_time->tm_sec;
	/**************End************/ 
}
long getdifftimeval (void)
{
	/*************Begin***********/
	struct timeval current,next;
    gettimeofday (&current, NULL);
	func();
	gettimeofday (&next, NULL);
	return (next.tv_sec-current.tv_sec)*1000*1000+next.tv_usec-current.tv_usec;
	/**************End************/
}

第3关 Linux 时间定时器

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>

void func (void);
static int count = 0;//the number of calling loopevent 

void loopevent (int signo)
{
	/************Begin************/
	if(signo==SIGPROF){

        func();
        count++;
    }
	if(count==5){
        struct itimerval it;
        it.it_interval.tv_sec = 0;
        it.it_interval.tv_usec = 0;
        it.it_value.tv_sec = 0;
        it.it_value.tv_usec = 0;
        setitimer(ITIMER_REAL, &it, NULL);
    }
	/*************End*************/
}
void setlocaltimer (void)
{
	/************Begin************/
	signal(SIGPROF , loopevent);
	struct timeval tv_interval = {1, 0};
    struct timeval tv_value = {3, 0};
    struct itimerval it;
    it.it_interval = tv_interval;
    it.it_value = tv_value;	
	setitimer(ITIMER_PROF , &it, NULL);
	/*************End*************/
}

Linux之文件操作

第1关 文件的创建

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main()
{
    /********** BEGIN **********/
    int ret=creat("testFile",S_IRUSR|S_IWUSR|S_IRGRP| S_IXGRP | S_IXOTH);
    if(ret==-1){
        printf("创建文件失败\n");
    }
    else{
        printf("创建文件失败\n");
    }
    /********** END **********/
    return 0;
}

第2关 文件打开与关闭

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

/************************
 * fileName: 需要被打开的文件路径
*************************/
int open_File(char *fileName)
{
	int fd = 0;   //存放文件描述符
	/********** BEGIN **********/
    fd=open(fileName,O_RDONLY);
	/********** END **********/

	return fd;
}

/************************
 * fd: 需要被关闭的文件描述符
*************************/
void close_File(int fd)
{
	/********** BEGIN **********/
	int ret = close(fd);
    if(ret==-1){
        printf("关闭文件失败\n");
    }
    else
    {
        printf("关闭文件成功\n");
    }
	/********** END **********/
}

第3关 文件读写操作

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

/************************
 * fd: 被打开文件的描述符
 * buf: 被写入字符串指针
*************************/
int write_File(int fd, char *buf)
{
	int writeSize = 0; //返回实际写入的字符个数

	/********** BEGIN **********/
    writeSize=write(fd,buf,strlen(buf));
   
	/********** END **********/

	return writeSize;
}

/************************
 * fd: 被打开文件的描述符
 * buf: 存放读取的字符串指针(假设buf足够大)
*************************/
int readLine(int fd, char *buf)
{
	int readSize = 0;  //返回实际读取的字符个数
	//提示:使用while循环每次只读取一个字符,判断该字符是否为换行符或者是否已经读取到文件末尾(读取到文件末尾返回值为0)
	/********** BEGIN **********/
	
    int result=-1;
    if(fd!=-1){
        while((result=read(fd,&buf[readSize],1))==1){
            if(buf[readSize]=='\n'){
                buf[readSize]='\0';
                break;
            }
            readSize++;
        }
    }
    if(result==-1) return result;
    else 
	/********** END **********/
	return readSize;
}

第4关 文件的删除

#include <stdio.h>
int main()
{
	/********** BEGIN **********/
    int ret = unlink("testFile");
    if (ret == -1)
    {
        printf("删除文件失败\n");
    }
    else
    {
        printf("删除文件成功\n");
    }	
	/********** END **********/
	return 0;
}

Linux进程控制

第1关 进程等待

#include <stdio.h>
#include <stdlib.h>
#include <string.h>  
#include <unistd.h> 
#include<sys/types.h> 
#include<sys/wait.h>

int g_i4event;
int process_wait(void)
{
    /********Begin********/
    pid_t pid = fork();
    g_i4event=1;
    if(pid==0){
        sleep(3);  
    }
    else{
        sleep(1);
        g_i4event=2;
        wait(NULL);
        g_i4event=3;
    }
     return 0;
    /*********End*********/
}

int process_waitpid(void)
{
    /********Begin********/
    pid_t pid = fork();
    g_i4event=1;
    if(pid==0){
        sleep(3);
    }
    else{
        sleep(1);
        g_i4event=2;
        waitpid(pid,NULL,0);
        g_i4event=3;
    }
    return 0;
    /*********End*********/
}

第2关 进程退出控制

#include <stdio.h>
#include <stdlib.h>
#include <string.h>  
#include <unistd.h> 
#include<sys/types.h> 
#include<sys/wait.h>
int g_i4event;
int father_son(void)
{
    /********Begin********/
	pid_t pid=fork();
    g_i4event=1;
    if(pid>0){
        sleep(1);
        g_i4event=2;      
    }
    else{
        sleep(2);
    }
    /*********End*********/
}
int son_father_nowait(void)
{
    /********Begin********/
	pid_t pid=fork();
	g_i4event=1;
    if(pid==0){
        sleep(1);
    }
    else{
        sleep(2);
        g_i4event=3;
    }
    /*********End*********/
}
int son_father_wait(void)
{
    /********Begin********/
	pid_t pid=fork();
	g_i4event=1;
    if(pid==0){
        sleep(1);  
    }
    else{
        wait(NULL);
        sleep(1);
        g_i4event=4;          
    }	
    /*********End*********/
}

第3关 system系统调用

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_i4event;
int do_system(void)
{
    /********Begin********/
	if(system("touch test.dat")!=-1)
    {
        g_i4event=1;
        return 0;
    }
    return -1;
    /*********End*********/
}

Linux高级进程通信

第1关 socket之本地通信

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

int localsocket_test(const char *buffer, char *recv_buff, int length)
{
	/*********begin***********/
    static struct sockaddr_un srv_addr;
    // creat unix socket
    int connect_fd = socket(PF_UNIX,SOCK_STREAM,0);
    if(connect_fd < 0)
    {
        perror("cannot creat socket");
        return -1;
    }
    srv_addr.sun_family = AF_UNIX;
    strncpy(srv_addr.sun_path, "./socket_test", strlen("./socket_test"));
    //connect server
    int ret = connect(connect_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
    if (ret < 0)
    {
        perror("cannot connect server");
        close(connect_fd);
        return -1;
    }
    if(0 > write(connect_fd, buffer, strlen(buffer)))
    {
        perror("send message failed\n");
        close(connect_fd);
        return -1;
    }
    if(0 < read(connect_fd, recv_buff, length))
    {
        ret = 0;
    }
    else
    {
        ret = -1;
    }
    close(connect_fd);
    return ret;
	/**********end************/
}

第2关 命名管道

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>

void namepipe_commu(const char *buffer)
{
	/***********begin***********/
	int fd;
    int w_num;
	if((mkfifo("./my_fifo",0777)<0))
    {
        printf("cannot create fifo...\n");
        exit(1);
    }
    //以阻塞型只写方式打开fifo
    fd=open("./my_fifo",O_WRONLY);
    w_num=write(fd,buffer,strlen(buffer));
	/***********end***********/
}

第3关 消息队列

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

struct msgbuf
{
    long mytype;
    char bookname[100];
};

void mq_commu (void)
{
	/*********Begin*********/
	//创建消息队列
    int msgid = msgget((key_t)0x1234, 0666 | IPC_CREAT);

    struct msgbuf data[4];
    int i;
    for(i=0;i<4;i++){
        data[i].mytype=66;
    }

    strcpy(data[0].bookname, "C");
    strcpy(data[1].bookname, "Linux");
    strcpy(data[2].bookname, "Makefile");
    strcpy(data[3].bookname, "End");

    for(i=0;i<4;i++){
        msgsnd(msgid, &data[i], sizeof(struct msgbuf)-sizeof(long), 0);
        if(strcmp(data[i].bookname,"End")==0){
            break;
        }
        sleep(1);
    }	
	/**********End**********/
}

Linux之线程管理

第1关 创建线程

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

/************************
 * 参数start_routine: 函数指针,用于指向线程函数
 * 参数arg: 是线程函数的参数
 * 返回值: 返回线程ID
*************************/
pthread_t createThread(void *(*start_routine) (void *), void *arg)
{
	pthread_t thread;
	/********** BEGIN **********/
	 int ret = pthread_create(&thread, NULL, start_routine, arg);
	/********** END **********/
	return thread;
}

第2关 线程挂起

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

/************************
 * 参数thread: 需要等待结束的线程ID号
 * 返回值: 等待成功返回0,失败返回-1
 * 提示: 忽略线程返回值
*************************/
int waitThread(pthread_t thread)
{
	int ret = -1;
	/********** BEGIN **********/
    if(pthread_join(thread, NULL) == 0)
    {      
        return 0;
    }
    else
	/********** END **********/
	return ret;
}

第3关 线程终止

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

/************************
 * 参数thread: 需要等待结束的线程ID号
 * 返回值: 等待成功返回0,失败返回-1
 * 提示: 忽略线程返回值
*************************/
int cancelThread(pthread_t thread)
{
	int ret = -1;
	/********** BEGIN **********/
    if(pthread_cancel(thread)==0)return 0;
	else
	/********** END **********/
	return ret;
}

Linux之线程同步一

第1关 互斥锁

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

//全局互斥锁变量
extern pthread_mutex_t mutex;

//全局共享变量
extern char *buffer[3];
extern int position;

/************************
 * 参数arg: 是线程函数的参数
*************************/
void *ThreadHandler(void *arg)
{
	/********** BEGIN **********/
	 pthread_mutex_lock(&mutex);
	/********** END **********/
	
	buffer[position] = (char *)arg;
	sleep(1);
	position++;
	
	/********** BEGIN **********/
	pthread_mutex_unlock(&mutex);	
	/********** END **********/
	pthread_exit(NULL);
}

第2关 自旋锁

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

//全局自旋锁变量
extern pthread_spinlock_t lock;

//全局共享变量
extern char *buffer[3];
extern int position;

/************************
 * 参数arg: 是线程函数的参数
*************************/
void *ThreadHandler(void *arg)
{
	/********** BEGIN **********/
	pthread_spin_lock(&lock);
	/********** END **********/

	buffer[position] = (char *)arg;
	sleep(1);
	position++;

	/********** BEGIN **********/
	pthread_spin_unlock(&lock);
	/********** END **********/
	pthread_exit(NULL);
}

第3关 条件变量

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

//全局互斥锁变量和条件变量
extern pthread_mutex_t mutex;
extern pthread_cond_t cond;

//全局共享变量
extern char *buffer[3];
extern int position;
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
/************************
 * 参数arg: 是线程函数的参数
*************************/
void *ThreadHandler1(void *arg)
{
	int i;
	for(i = 0; i < 3; i++)
	{
		usleep(500);
		position++;
		//通知ThreadHandler2函数执行赋值操作
		/********** BEGIN **********/
		pthread_cond_signal(&has_product);
		/********** END **********/
	}
	pthread_exit(NULL);
}

/************************
 * 参数arg: 是线程函数的参数
*************************/
void *ThreadHandler2(void *arg)
{
	/********** BEGIN **********/
	pthread_mutex_lock(&mutex);
    pthread_cond_wait(&has_product, &mutex);
	/********** END **********/

	buffer[position] = (char *)arg;
	
	/********** BEGIN **********/
	pthread_mutex_unlock(&mutex);
	/********** END **********/
	pthread_exit(NULL);
}

第4关 项目实战

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

struct Data
{
    int number;    //存放生产的数据
    struct Data *next;
};

//定义数据区头和尾
extern struct Data *beginData;    

const int max_number = 10;   //生产者与消费者的最大生产和消费任务
int consumer_number = 0;     //消费者已经消费的任务数
//全局互斥锁变量和条件变量
extern pthread_mutex_t mutex;
extern pthread_cond_t cond;

/************************
 * 参数arg: 是线程函数的参数
*************************/
void *Consumer(void *arg)
{
	while(1)
	{
		/********** BEGIN **********/
		pthread_mutex_lock(&mutex);
		while(beginData == NULL)
        {  
            pthread_cond_wait(&cond, &mutex);
        }
        if(beginData->number==-1){
            pthread_mutex_unlock(&mutex);
            pthread_exit(NULL);
        }      
        //消费数据
        printf("%d\n", beginData->number);
        consumer_number++;
        //将消费后的数据释放掉
        struct msg *tmp = beginData;
        beginData = beginData->next;
        free(tmp);
        pthread_mutex_unlock(&mutex);	
		/********** END **********/
	}
	pthread_exit(NULL);
}

Linux之网络编程(TCP)

第1关 TCP套接字创建与端口绑定

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

/************************
 * sockfd: 已经创建的套接字
 * port: 需要绑定的端口号
 * 返回值: 调用成功返回0,否则返回-1
*************************/
int bindSocket(int sockfd, unsigned short port)
{
	int ret = -1;
	/********** BEGIN **********/
    struct sockaddr_in addr;
    bzero(&addr, sizeof(addr));    //清空
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
	ret=bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
	if(ret){
        return 0;
    }
    else
	/********** END **********/
	return ret;
}

第2关 TCP监听与接收连接

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main()
{
	int sockfd;
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd == -1)
	{
		printf("创建TCP套接字失败: %s\n", strerror(errno));
		return -1;
	}
	struct sockaddr_in addr;
	bzero(&addr, sizeof(addr));    //清空
	addr.sin_family = AF_INET;
	addr.sin_port = htons(8888);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//与8888端口进行绑定
	if(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
	{
		printf("绑定端口失败: %s\n", strerror(errno));
		return -1;
	}

	//监听8888端口,并设置最大监听个数大于1
	/********** BEGIN **********/
	 if(listen(sockfd, 1) == -1)
    {
        printf("监听端口%d失败: %s\n", 8888, strerror(errno));
        return -1;
    }
    else
    {
        printf("监听%d端口中...\n", 8888);
    }
	
	/********** END **********/

	//接受来自客户端的第一个连接请求
	/********** BEGIN **********/
     int clientSockfd;
    struct sockaddr_in clientAddr;
    socklen_t clientAddrSize = sizeof(struct sockaddr_in);
	if((clientSockfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrSize)) == -1)
    {
        printf("接受客户端请求失败: %s\n", strerror(errno));
        return -1;
    }
    else
    {
        printf("接受客户端请求成功\n");
        //inet_ntoa函数将网络地址转换成.点隔的字符串格式
        printf("客户端的IP地址:%s \t 端口:%d\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
    }	
	/********** END **********/
	close(sockfd);	
	return 0;
}

第3关 TCP连接的建立与终止

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define SERVER_IP "127.0.0.1"
/************************
 * ipAddr: 远程服务器的IP地址
 * port: 远程服务器的端口
*************************/
void connectSocket(char *ipAddr, unsigned short port)
{
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd == -1)
	{
		printf("创建TCP套接字失败: %s\n", strerror(errno));
		return ;
	}	
	//连接到指定的服务器
	/********** BEGIN **********/
    struct sockaddr_in servAddr;
    bzero(&servAddr, sizeof(servAddr));    //清空
    servAddr.sin_family = AF_INET;
    servAddr.sin_port = htons(port);
    //使用inet_addr函数将点分十进制的IP转换成一个长整数型数
    servAddr.sin_addr.s_addr = inet_addr(ipAddr);
    //连接服务器
    if(connect(sockfd, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1)
    {
        printf("请求连接服务器失败: %s\n", strerror(errno));
        return -1;
    }
    else
    {
        printf("请求连接%s:%d成功\n", ipAddr, port);
    }	
	/********** END **********/

	close(sockfd);
}

第4关 TCP数据传送

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#define PORT 8888

int main()
{
	int sockfd;
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd == -1)
	{
		return -1;
	}
	struct sockaddr_in addr;
	bzero(&addr, sizeof(addr));    //清空
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//与PORT端口进行绑定
	if(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
	{
		return -1;
	}
	//监听PORT端口,并设置最大监听个数为5
	if(listen(sockfd, 5) == -1)
	{
		return -1;
	}
	int clientSockfd;
	struct sockaddr_in clientAddr;
	socklen_t clientAddrSize = sizeof(struct sockaddr_in);
	//接受连接请求
	if((clientSockfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrSize)) == -1)
	{
		return -1;
	}
	else
	{
		char data[100];
		//接收客户端传来的数据,并打印出来(提示:换行打印)
		//同时将接收到的数据原样发送给客户端
		/********** BEGIN **********/
		memset(data,0,sizeof(data));
        while(recv(clientSockfd,data,sizeof(data),0)>0){
            printf("%s\n",data);
            send(clientSockfd,data,strlen(data),0);
           memset(data,0,sizeof(data));
        }
		/********** END **********/
	}
	close(clientSockfd);
	close(sockfd);
	
	return 0;
}

Linux之网络编程(UDP)

第1关 UDP套接字创建与端口绑定

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

/************************
 * port: 需要绑定的端口号
 * 返回值: 调用成功返回0,否则返回-1
*************************/
int UDPSocket(unsigned short port)
{
	int ret = -1;
	/********** BEGIN **********/
	int sockfd= socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd == -1)
    {
        printf("创建UDP套接字失败: %s\n", strerror(errno));
        return ret;
    }
    else
    {
        printf("创建UDP套接字成功\n");
         ret=0;
    }
    struct sockaddr_in addr;
	bzero(&addr, sizeof(addr));    //清空
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//与port端口进行绑定
	if(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
	{
        printf("绑定端口失败: %s\n", strerror(errno));
		return -1;
	}	
	/********** END **********/
	return ret;
}

第2关 UDP数据传送

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#define PORT 8888

int main()
{
	int sockfd;
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sockfd == -1)
	{
		return -1;
	}
	struct sockaddr_in addr;
	bzero(&addr, sizeof(addr));    //清空
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//与PORT端口进行绑定
	if(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
	{
		return -1;
	}
	char data[100];
	//接收客户端传来的数据,并打印出来(提示:换行打印)
	//同时将接收到的数据原样发送给客户端
	//当接收到"exit"字符串时,退出当前程序,不打印出"exit"字符串
	//提示:在每次接收字符串前要将存放字符串的变量清空
	/********** BEGIN **********/
	 struct sockaddr_in clientAddr;
    int clientAddrLen = sizeof(clientAddr);
    memset(data,0,sizeof(data));
    while(recvfrom(sockfd, data, sizeof(data), 0, (struct sockaddr *)&clientAddr, &clientAddrLen) > 0)
    {
        if(strcasecmp(data, "exit") == 0) break;
        sendto(sockfd, data, sizeof(data), 0, (struct sockaddr *)&clientAddr, sizeof(clientAddr));  //发送数据    
        printf("%s\n", data);
        memset(data,0,sizeof(data));
    }
	/********** END **********/
	close(sockfd);
	return 0;
}

第3关 项目实战

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

//定义数据块大小
char data[16];
//定义服务器端口和服务器地址
#define PORT 8889
#define SERVER_IP "127.0.0.1"

int main(int argc, char *argv[])
{
	int sockfd;
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sockfd == -1)
	{
		return -1;
	}
	struct sockaddr_in servAddr;
	int servAddrLen = sizeof(servAddr);
	bzero(&servAddr, sizeof(servAddr));
	servAddr.sin_family = AF_INET;
	servAddr.sin_port = htons(PORT);
	servAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
	
	//由用户传入的要下载文件的名称
	char *downLoadFileName = argv[1];
	printf("%s\n", argv[1]);
	//先在本地创建要下载的文件
	int fd = open(downLoadFileName, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
	//向服务器发送要上传文件的名称
	sendto(sockfd, downLoadFileName, strlen(downLoadFileName), 0, (struct sockaddr *)&servAddr, servAddrLen); 	
    /********** BEGIN **********/
   	struct sockaddr_in clientAddr;
    int clientAddrLen = sizeof(clientAddr);
    int recvLen;
	//接收来自客户端发来的数据
    while((recvLen = recvfrom(sockfd, data, sizeof(data), 0, (struct sockaddr *)&servAddr, &servAddrLen)) > 0)
    {
        //根据自定义的协议来判断客户端发送来的数据块类型
        if(data[0] == 'e')
        {
            //上传文件完成,关闭当前打开的文件
            close(fd);
            break;
        }
        else
        {
            //数据块为上传文件的内容,将内容写入到新创建的文件中
            //因为data的第一个字符为文件块类型,所以只需从第二个字符开始写文件
            write(fd, &(data[1]), recvLen - 1);
        }
        //给客户端回复一个接收确认的标识OK
        sendto(sockfd, "OK", strlen("OK"), 0, (struct sockaddr *)&servAddr, servAddrLen);
        memset(data, 0, sizeof(data));
    }
	/********** END **********/
	close(sockfd);	
	return 0;
}

基于TCP协议的Client/Server程序开发实例

第1关 服务器端程序开发

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#define PORT 8888

int main()
{
	int sockfd;
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd == -1)
	{
		return -1;
	}
	struct sockaddr_in addr;
	bzero(&addr, sizeof(addr));    //清空
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//设置套接字属性
	int reuse = 1;
	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
	{
		perror("设置socket套接字错误\n");
		return "-1";
	}
	//与PORT端口进行绑定
	if(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
	{
		return -1;
	}
	
	//监听PORT端口,并设置最大监听个数为5
	if(listen(sockfd, 5) == -1)
	{
		return -1;
	}
	
	int clientSockfd;
	struct sockaddr_in clientAddr;
	socklen_t clientAddrSize = sizeof(struct sockaddr_in);
	int pid;
	while(1)
	{
		//接受连接请求
		if((clientSockfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrSize)) == -1)
		{
			return -1;
		}
		else
		{
			//接收客户端传来的数据,同时将接收到的数据原样发送给客户端
			/********** BEGIN **********/
			pid = fork();
            if(pid == -1)
            {
                printf("创建进程失败(%s)\n", strerror(errno));
                return -1;
            }
            else if(pid == 0)
            {
                //子进程
                close(sockfd);   //关闭服务器套接字
                char userInput[100];
                memset(userInput, 0, sizeof(userInput));
                while(recv(clientSockfd, userInput, sizeof(userInput), 0) > 0)
                {
                    if(strcasecmp(userInput, "exit") == 0)
                        break;
                    printf("%s\n", userInput);
                    send(clientSockfd, userInput, strlen(userInput), 0);  //发送数据
                    memset(userInput, 0, sizeof(userInput));  //清空上次接收的缓存
                }
                close(clientSockfd);  //关闭客户端连接
            }
            else
            {
            //父进程
                close(clientSockfd);  //关闭客户端连接
            }
        /********** END **********/
		}
	}
	close(sockfd);
	return 0;
}

第2关 基于TCP协议的文件上传下载工具开发

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

//定义服务器端口
#define PORT 8889

void *downloadFileServer(void *arg)
{
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd == -1)
	{
		printf("创建TCP套接字失败: %s\n", strerror(errno));
		return "-1";
	}
	struct sockaddr_in addr;
	bzero(&addr, sizeof(addr));    //清空
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//设置套接字属性
	int reuse = 1;
	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
	{
		perror("设置socket套接字错误\n");
		return "-1";
	}
	//绑定本地8889端口
	if(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
	{
		printf("绑定端口失败: %s\n", strerror(errno));
		return "-1";
	}

	//监听8889s口,并设置最大监听个数为10
	if(listen(sockfd, 10) == -1)
	{
		printf("监听端口%d失败: %s\n", PORT, strerror(errno));
		return "-1";
	}

	//存放客户端主机信息
	struct sockaddr_in clientAddr;
	int clientAddrLen = sizeof(clientAddr);
	int clientSockfd;
	pid_t pid;
	while(1)
	{
		//监听客户端连接请求
		if((clientSockfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen)) == -1)
		{
			printf("接受客户端请求失败: %s\n", strerror(errno));
			return "-1";
		}
		else
		{
			/********** BEGIN **********/
            char downLoadFileName[100];
            char data[16];
            pid = fork();
            if(pid == -1)
            {
                printf("创建进程失败(%s)\n", strerror(errno));
                return "-1";
            }else if(pid == 0){
                close(sockfd); //关闭服务器套接字
                recv(clientSockfd, downLoadFileName, sizeof(downLoadFileName), 0);
                send(clientSockfd, downLoadFileName, strlen(downLoadFileName), 0);
                int fd = open(downLoadFileName, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 
                int recvLen;
                memset(data, 0, sizeof(data));
                while((recvLen = recv(clientSockfd, data, sizeof(data),0)) > 0)
                {
                    if(data[0] == 'c')
                    {
                        write(fd, &(data[1]), recvLen - 1);
                        send(clientSockfd, "OK", strlen("OK"), 0);
                    }
                    else
                    {
                        close(fd);  //关闭文件
                        break;
                    }
                    memset(data, 0, sizeof(data));
                    }
                close(clientSockfd);
            }else{
                close(clientSockfd); 
            }
			/********** END **********/
		}
	}	
	close(sockfd);
	return "0";
}

交叉编译busybox

第1关 交叉编译工具的安装

apt-get update
apt-get install gcc-arm-linux-gnueabi
arm-linux-gnueabi-gcc -v

第2关 宿主机上编译BusyBox

apt-get install libncurses5-dev
cd /data/workspace/myshixun/
tar -jxvf busybox-1.2.2.tar.bz2
cd busybox-1.2.2
make menuconfig
依次进入Busybox Settings(设置选项),编译(Build Options),选中编译为静态库(Build BusyBox as a static binary (no shared libs)) 用Y选中
设置Shell (Shells),选择ash
执行命令完成编译:make
运行Busybox命令格式如下:./busybox 命令
运行如下命令,观察执行结果
./busybox
./busybox echo hello world
预期输出:
hello busybox

第3关 交叉编译运行BusyBox

(1)通过如下命令设置清除前期宿主机上的编译结果文件:make clean

(2)设置交叉编译工具前缀选项
使用如下命令配置BusyBox编译选项:make menuconfig
依次进入BusyBox设置(BusyBox Setting),编译选项(Build Option)中选择“是否使用交叉编译器?”(Do you want to build BusyBox with a Cross Compile ”),并将交叉编译器前缀设置为arm-linux-gnueabi-
(3)根据需要配置BusyBox的工具选项:在busybox中编译编辑工具vi
(4)使用如下命令完成交叉编译:make
(1)使用如下命令直接运行BusyBox
./busybox echo ‘hello busybox’
能看到ps命令的执行结果吗?看不到
(2)使用如下命令利用QEMU仿真器运行busybox
qemu-arm -L /usr/arm-linux-gnueabi -cpu cortex-a15 busybox echo ‘hello busybox’
(3)仿真器中运行busybox中的vi工具
qemu-arm -L /usr/arm-linux-gnueabi -cpu cortex-a15 busybox vi

本文是Linux 下C 语言编程入门教程。主要介绍了Linux 的发展与特点、C语言的基础知识、Linux 程序设计基础知识及其下C 语言编程环境、Linux 程序设计的特点及其下C 语言编程风格等。   Linux 作为一个优秀的操作系统,一项非常重要的功能就是支持系统调用尤其是支持C语言的系统调用功能十分的方便、快捷。C 语言具有高速、灵活、简洁、可移植性好等特点,从而很快成为了世界上最受欢迎的编程语言之一。   1 Linux 的发展和特点 Linux 最初是专门为基于Intel 处理器的个人计算机而设计的。Linux 的前身是赫尔辛基大学( University of Helsinki )一位名叫Linus Torvald 的计算机科学系学生的个人项目。Linus 把Linux 建立在一个基于PC 机上运行的、缩小型的、名为Minux 的UNIX 基础之上, Minux 本身具有UNIX 的各种特性, 这使得以Minux 做参照而产生的Linux 继承并更突出了UNIX 的各种优良特性。当时LinusTorvold 通过USENET (新闻组)宣布了Linux 是一个免费的系统,并指出它主要在x86 电脑上使用,希望大家一起来将它完善, 并将源代码放到了芬兰的FTP 站点上供人免费下载。本来他想把这个系统称为freax ,可是FTP 的工作人员认为这是Linus 的Minux ,就用Linux 这个子目录来存放,于是它就成了“ Linux ”。这时的Linux 只有核心程序(内核) ,还不能称作是完整的系统,不过由于许多专业用户(主要是程序员)自愿地开发它的应用程序,并借助Internet 拿出来让大家一起修改一起完善,所以它的周边的程序也越来越多,功能也越来越强大, Linux 本身也就这样逐渐发展壮大起来。近年来,Linux 操作系统得到了迅猛地发展,在短短的几年之内就包含了UNIX 的全部功能和特性,在中高端服务器上得到了广泛的应用,国际上很多有名的硬、软件厂商都与之结盟、捆绑,将之用作自己的操作系统Linux 操作系统得到了非常迅猛地发展,这与Linux 具有的良好特性是分不开的。     Linux 操作系统的特点可总结为以下几点:   1. 自由软件   Linux 项目从一开始就与GNU 项目紧密结合起来, 它的许多重要组成部分直接来自GNU 项目。Linux 可以说是作为开放源码的自由软件的代表,便于定制和再开发。在遵从GPL 版权协议的条件下,各部门、企业、单位或个人就可以免费得到Linux 源程序,并根据自己的实际需要和使用环境对Linux 系统进行裁剪、扩充、修改,再开发和发布程序的源码,并公布在Internet 上。这样就激发了世界范围内热衷于计算机事业的人们的创造力。通过Internet ,这一软件的传播和使用迅速扩大。因为Linux 操作系统可以从互联网上很方便地免费下载,这样就可以省下购买Windows 操作系统的一笔不小的资金(正版Windows 很昂贵) 。且由于可以得到Linux 的源码,所以操作系统的内部逻辑是可见的,这样就可以根据源码准确地查明故障产生的原因,及时采取相应对策。   2. 开放性   开放性是指系统遵循世界标准规范,特别是遵循开放系统互连( OSI )国际标准。凡遵循国际标准所开发的硬件和软件,都能彼此兼容,可方便地实现互连。   3. 多用户   系统资源可以被不同用户各自拥有使用,即每个用户对自己的资源(例如:文件、设备)有特定的权限,互不影响,允许多个用户从相同或不同的终端上同时使用同一台计算机。   4. 多任务   它是指计算机允许多个程序同时执行,而且各个程序的运行互相独立。Linux 系统调度每一个进程,平等地访问微处理器。由于CPU 的处理速度非常快,其结果是,启动的应用程序看起来好像在并行运行。事实上,从处理器执行一个应用程序中的一组指令到Linux 调度微处理器再次运行这个程序之间只有很短的时间延迟,用户是感觉不出来的。Linux 充分利用了X86CPU 的任务切换机制,实现了真正多任务、多用户环境,允许多个用户同时执行不同的程序,并且可以给紧急任务以较高的优先级。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值