文章目录
- 嵌入式Linux应用开发入门
- C语言程序设计编辑与调试环境
- Linux之C编程入门
- Linux时间编程
- Linux之文件操作
- Linux进程控制
- Linux高级进程通信
- Linux之线程管理
- Linux之线程同步一
- Linux之网络编程(TCP)
- Linux之网络编程(UDP)
- 基于TCP协议的Client/Server程序开发实例
- 交叉编译busybox
嵌入式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(¤t));
memcpy(tm_time, gmtime(¤t),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 (¤t, 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