头歌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
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

上一篇:简洁的c++http协议获取内容(一)


下一篇:Socket原理详解