让我们的ARM开发板也能“聊天”
2012-11-13 12:45
134 查看
转载申明来自: http://mcuos.com/thread-8305-1-1.html
原文作者: 郭文学 <guowenxue@gmail.com QQ:281143292>
关于凌云嵌入式: http://mcuos.com/thread-7178-1-1.html
由于项目的需要,今天给刚开始接触Linux编程的同事写了一个非常简单的socket
sample程序(代码原型来自W.
Richard Stevens的《Unix Network Program 3rd》,在这里向Richard Stevens致敬!),但这个“小程序”里暗藏着“大道理”:他能够让我们的开发板“聊天”,不相信?那你就认真分析一下:
在我们服务器上跑的服务器程序:
[guowenxue@centos6 unp]$ cat socket_server.c
/*********************************************************************************
* Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com> * All rights reserved.
* Thanks To: W. Richard Stevens, who bring me to the Linux program world!*
* Filename: socket_server.c
* Description: This is a sample socket server demo program.
*
* Version: 1.0.0(06/08/2012~)
* Author: Guo Wenxue <guowenxue@gmail.com>
* ChangeLog: 1, Release initial version on "06/08/2012 02:50:51 PM"
*
********************************************************************************/
/* Some Unix Program Standard head file */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* Socket Program head file */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> /* sockaddr_in{} and other Internet define */
/* strerror(), perror(), errno head file*/
#include <errno.h>
#include <time.h>
#define DAYTIME_SERV_PORT 8888
#define MAX_BUF_SIZE 1024
#define LISTENQ 1024 /* 2nd argument to listen () */
/* Argc is the program linux running command arguments count, and argv is
* the arguments string value. All of the arguments take as string.
* For example:
* If we run this program as "./socket_server 13", there are two
* arguments, so argc=2, argv[0] is the first argument, which is string value
* "./socket_server" and argv[1] is the second argment, which is string value
* "13".
*/
int main(int argc, char **argv)
{
int listenfd, connfd;
char send_buf[MAX_BUF_SIZE];
struct sockaddr_in servaddr;
time_t ticks;
int serv_port;
if(2 == argc)
{
/*If there is a argument, then we take it as the server port number, and it's a
*string value, so we use atoi() function to convert it to int type.*/
serv_port = atoi(argv[1]);
}
else
{
serv_port = DAYTIME_SERV_PORT;
printf("Another Usage: %s [ServerPort]\n", argv[0]);
}
/*
* Open an IPV4(AF_INET) TCP(SOCK_STREAM) Socket File Description(listenfd), UDP socket
* should use SOCK_DGRAM,We can use linux command "man socket" to see this function manual
*/
if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
/* strerror() is the 1st way to display the failure reason, argument
* errno is a globle variable defined in <errno.h>, we can use linux command
* "man strerror" to see this function manual*/
printf("Use socket() to create a TCP socket failure: %s\n", strerror(errno));
return -1;
}
/* Now we set the Server Information, include IPV4 or IPV6, Listen IP address and Port */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET; /* Set it as IPV4 protocal */
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Listen all the local IP address */
servaddr.sin_port = htons(serv_port); /* daytime server port */
/*
* When a socket is created with socket(2), it exists in a name space (address family) but
* has no address assigned to it. bind() assigns the address specified to by addr to the
* socket referred to by the file descriptor listenfd. We can use Linux command "man 2 bind"
* to see this function manual.
*/
if(bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
{
printf("Use bind() to bind the TCP socket failure: %s\n", strerror(errno));
goto CleanUp;
}
/*
* listen() marks the socket referred to by listenfd as a passive socket, that is, as a socket
* that will be used to accept incoming connection requests using accept(2). We can use Linux
* command "man listen" to see this function manual.
*/
if(listen(listenfd, LISTENQ) < 0)
{
printf("Use bind() to bind the TCP socket failure: %s\n", strerror(errno));
goto CleanUp;
}
printf("%s server start to listen port %d\n", argv[0],serv_port);
for ( ; ; )
{
/*
* The accept() system call is used with connection-based socket types (SOCK_STREAM, SOCK_SEQPACKET).
* It extracts the first connection request on the queue of pending connections for the listening
* socket linstenfd, creates a new connected socket(connfd), and returns a new file descriptor referring
* to that socket. The newly created socket is not in the listening state. The original socket
* listenfd is unaffected by this call.
*/
if( (connfd=accept(listenfd, (struct sockaddr *)NULL, NULL)) > 0)
{
ticks = time(NULL); /* Get current system time */
snprintf(send_buf, sizeof(send_buf), "%.24s\r\n", ctime(&ticks));
if(write(connfd, send_buf, strlen(send_buf)) < 0)
{
printf("Write current time to client failure: %s\n", strerror(errno));
}
close(connfd);
}
}
CleanUp:
close(listenfd); /* We must close socket File Description when program exit*/
return 0;
}
复制代码
在我们的ARM开发板上跑的客户端程序:
/*********************************************************************************
* Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com>
* All rights reserved.* Thanks To: W. Richard Stevens, who bring me to the Linux program world!
*
* Filename: socket_client.c
* Description: This is a sample socket client demo program.
*
* Version: 1.0.0(06/08/2012~)
* Author: Guo Wenxue <guowenxue@gmail.com>
* ChangeLog: 1, Release initial version on "06/08/2012 02:50:51 PM"
*
********************************************************************************/
/* Some Unix Program Standard head file */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* Socket Program head file */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> /* sockaddr_in{} and other Internet define */
#include <errno.h> /* strerror(), perror(), errno head file*/
#include <arpa/inet.h> /* For inet_pton() */
#define DAYTIME_SERV_PORT 8888
#define MAX_BUF_SIZE 1024
/* Argc is the program linux running command arguments count, and argv is
* the arguments string value. All of the arguments take as string.
* For example:
* If we run this program as "./socket_client 192.168.3.15", there are two
* arguments, so argc=2, argv[0] is the first argument, which is string value
* "./socket_client" and argv[1] is the second argment, which is string value
* "1921.68.3.15".
*/
int main(int argc, char **argv)
{
int sockfd, len, retval;
char recv_buf[MAX_BUF_SIZE];
struct sockaddr_in servaddr;
/* Check the arguments count, if No serverip address give as an argument,
* then program exit */
if(2 != argc)
{
printf("usage: %s <ServerIPaddress>\n", argv[0]);
printf("Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com>\n");
return -1;
}
/* Open an IPV4(AF_INET) TCP(SOCK_STREAM) Socket File Description, UDP socket should
* use SOCK_DGRAM,We can use linux command "man socket" to see this function manual
*/
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
/* strerror() is the 1st way to display the failure reason, argument
* errno is a globle variable defined in <errno.h>, we can use linux command
* "man strerror" to see this function manual*/
printf("Use socket() to create a TCP socket failure: %s\n", strerror(errno));
return -1;
}
/* Now we set the Server Information, include IPV4 or IPV6, Server Port, Server IP address */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET; /* Set it as IPV4 protocal */
servaddr.sin_port = htons(DAYTIME_SERV_PORT); /* Daytime server port*/
/* argv[1] we take as Server IP address, it's the second arguments in running command */
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
{
printf("Use inet_pton() to set the Server IP address failure.\n");
retval = -2;
goto CleanUp;
}
/* Now call connect() function to connect to the server, we can use linux command "man connect"
* to see this function manual */
printf("Connect to Server [%s:%d]\n", argv[1], DAYTIME_SERV_PORT);
if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
{
printf("Connect to the server [%s:%d] failure\n", argv[1], DAYTIME_SERV_PORT);
retval = -3;
goto CleanUp;
}
/* Once we connect to the server successfully, we can receive the data from the socket socekt */
while ( (len = read(sockfd, recv_buf, MAX_BUF_SIZE)) > 0)
{
recv_buf[len] = 0; /* null terminate */
printf("Get Time from server %s: %s\n", argv[1], recv_buf);
}
if( len < 0 )
{
/* perror() ss the 2nd way to display the failure reason */
perror("Read() from socket failure");
retval = -4;
goto CleanUp;
}
CleanUp:
close(sockfd); /* We must close socket File Description when program exit*/
return 0;
}
复制代码
源代码有了,我们开始编译,这里给了file和strip两个很有用的命令的用法:
让server端的程序在PC Linux上跑
[guowenxue@centos6 unp]$ gcc -static
socket_server.c -o socket_server
[guowenxue@centos6 unp]$ file socket_server
socket_server: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.18, not stripped
[guowenxue@centos6 unp]$ du -h socket_server
760K socket_server
[guowenxue@centos6 unp]$
[guowenxue@centos6 unp]$ file socket_server
socket_server: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.18, stripped
[guowenxue@centos6 unp]$ strip socket_server
[guowenxue@centos6 unp]$ du -h socket_server
688K socket_server
其实嵌入式应用程序开发,就是写完代码后的一个交叉编译的过程。那什么是交叉编译呢?简单的来说,就是用交叉编译器编译出来的程序,在另外一个处理器(如我们的ARM)上跑,而不是在本地处理器(如我们的X86)上跑。那怎么知道我们编译的程序是在X86上跑,还是在ARM平台上跑呢?那就好好研究一下file命令的输出。下面我们开始交叉编译client端程序:
[guowenxue@centos6 unp]$ /opt/buildroot-2011.11/arm926t/usr/bin/arm-linux-gcc socket_client.c -o socket_client.c
喜欢使用TAB键补齐命令的童鞋们,估计会经常碰到我上面这条悲摧的命令。如果你没碰到,够勇敢的话,可以试试。上面的命令会把编译生成的可执行文件覆盖我们的C源码文件socket_client.c.
我们使用file命令看看他的信息:
[guowenxue@centos6 unp]$ file socket_client.c
socket_client.c: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
好在哥们使用git管着我的源代码,别跟我说你不知道git/svn是啥?21世纪不知道git/svn的程序不是好程序员,如果你还真不知道,那么西元200年孙策就告诉我们,“外事不决找google,内事不决问baidu”。
[guowenxue@centos6 unp]$ git checkout socket_client.c
[guowenxue@centos6 unp]$ file socket_client.c
socket_client.c: ASCII C program text
噢,在git的帮助下,我胡汉三又回来啦!言归正传,上面通过一个失误讲解了git的一个小作用。下面来正经的:
[guowenxue@centos6 unp]$ /opt/buildroot-2011.11/arm926t/usr/bin/arm-linux-gcc -static socket_client.c -o socket_client
[guowenxue@centos6 unp]$ file socket_client
socket_client: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, not stripped
[guowenxue@centos6 unp]$ du -h socket_client
124K socket_client
通过file命令,我们可以看到,socket_client是32位小端字节序(LSB)上的ELF格式的可执行程序,在ARM上跑,是静态编译的(statically linked),没有strip. 如果没有strip,文件的大小为124K.
下面我们使用strip命令给他剥掉华丽的外衣后再看看文件类型和大小:
[guowenxue@centos6 unp]$ /opt/buildroot-2011.11/arm926t/usr/bin/arm-linux-strip socket_client
[guowenxue@centos6 unp]$ file socket_client
socket_client: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, stripped
[guowenxue@centos6 unp]$ du -h socket_client
76K socket_client
是ARM的就该放到ARM上跑,是X86的,我们就应该在X86上运行。是火星上的,我们就把它扔到火星上去:
PC端上,首先把ARM上跑的socket_client放到我们的tftp服务器根目录下去:
[guowenxue@centos6 unp]$ cp socket_client /tftp/
别说,你不知道怎么在Linux上假设tftp服务器,那好好看看我的这个文章吧:
http://mcuos.com/thread-7115-1-1.html
然后在本地Linux服务器上开始运行我们的服务器端程序:
[guowenxue@centos6 unp]$ ./socket_server
Another Usage: ./socket_server [ServerPort]
./socket_server server start to listen port 8888
完成PC端的工作,我们就要跑到ARM这颗火星上来处理client端了:
ARM上跑的是Linux,用的当时最新的3.3,不过现在已经out啦!
~ >: uname -a
Linux CoherentPlus 3.3.0 #1 Thu May 3 16:45:19 CST 2012 armv5tejl GNU/Linux
首先使用tftp命令下载我们的刚才编译出来的程序,192.168.1.78是我的Linux服务器IP地址,他开启了tftp服务,tftp服务的根目录是/tftp.
~ >: tftp -gr socket_client 192.168.1.78
socket_client 100% |***********************************************************************************| 77112 0:00:00 ETA
既然是Linux,运行之前,肯定要给他执行的权限咯。
~ >: chmod 777 socket_client
火星人开始跟地球人聊天了:“地球上的兄弟,把你们当前的时间告诉我吧!”
地球上的兄弟很爽快的答应:“哥们,我们现在的时间是Fri Jun 8 17:47:04 2012,欢迎光临!”
~ >: ./socket_client
usage: ./socket_client <ServerIPaddress>
Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com>
~ >: ./socket_client 192.168.1.78
Connect to Server [192.168.1.78:8888]
Get Time from server 192.168.1.78: Fri Jun 8 17:47:04 2012
~ >:
原文作者: 郭文学 <guowenxue@gmail.com QQ:281143292>
关于凌云嵌入式: http://mcuos.com/thread-7178-1-1.html
由于项目的需要,今天给刚开始接触Linux编程的同事写了一个非常简单的socket
sample程序(代码原型来自W.
Richard Stevens的《Unix Network Program 3rd》,在这里向Richard Stevens致敬!),但这个“小程序”里暗藏着“大道理”:他能够让我们的开发板“聊天”,不相信?那你就认真分析一下:
在我们服务器上跑的服务器程序:
[guowenxue@centos6 unp]$ cat socket_server.c
/*********************************************************************************
* Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com> * All rights reserved.
* Thanks To: W. Richard Stevens, who bring me to the Linux program world!*
* Filename: socket_server.c
* Description: This is a sample socket server demo program.
*
* Version: 1.0.0(06/08/2012~)
* Author: Guo Wenxue <guowenxue@gmail.com>
* ChangeLog: 1, Release initial version on "06/08/2012 02:50:51 PM"
*
********************************************************************************/
/* Some Unix Program Standard head file */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* Socket Program head file */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> /* sockaddr_in{} and other Internet define */
/* strerror(), perror(), errno head file*/
#include <errno.h>
#include <time.h>
#define DAYTIME_SERV_PORT 8888
#define MAX_BUF_SIZE 1024
#define LISTENQ 1024 /* 2nd argument to listen () */
/* Argc is the program linux running command arguments count, and argv is
* the arguments string value. All of the arguments take as string.
* For example:
* If we run this program as "./socket_server 13", there are two
* arguments, so argc=2, argv[0] is the first argument, which is string value
* "./socket_server" and argv[1] is the second argment, which is string value
* "13".
*/
int main(int argc, char **argv)
{
int listenfd, connfd;
char send_buf[MAX_BUF_SIZE];
struct sockaddr_in servaddr;
time_t ticks;
int serv_port;
if(2 == argc)
{
/*If there is a argument, then we take it as the server port number, and it's a
*string value, so we use atoi() function to convert it to int type.*/
serv_port = atoi(argv[1]);
}
else
{
serv_port = DAYTIME_SERV_PORT;
printf("Another Usage: %s [ServerPort]\n", argv[0]);
}
/*
* Open an IPV4(AF_INET) TCP(SOCK_STREAM) Socket File Description(listenfd), UDP socket
* should use SOCK_DGRAM,We can use linux command "man socket" to see this function manual
*/
if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
/* strerror() is the 1st way to display the failure reason, argument
* errno is a globle variable defined in <errno.h>, we can use linux command
* "man strerror" to see this function manual*/
printf("Use socket() to create a TCP socket failure: %s\n", strerror(errno));
return -1;
}
/* Now we set the Server Information, include IPV4 or IPV6, Listen IP address and Port */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET; /* Set it as IPV4 protocal */
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Listen all the local IP address */
servaddr.sin_port = htons(serv_port); /* daytime server port */
/*
* When a socket is created with socket(2), it exists in a name space (address family) but
* has no address assigned to it. bind() assigns the address specified to by addr to the
* socket referred to by the file descriptor listenfd. We can use Linux command "man 2 bind"
* to see this function manual.
*/
if(bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
{
printf("Use bind() to bind the TCP socket failure: %s\n", strerror(errno));
goto CleanUp;
}
/*
* listen() marks the socket referred to by listenfd as a passive socket, that is, as a socket
* that will be used to accept incoming connection requests using accept(2). We can use Linux
* command "man listen" to see this function manual.
*/
if(listen(listenfd, LISTENQ) < 0)
{
printf("Use bind() to bind the TCP socket failure: %s\n", strerror(errno));
goto CleanUp;
}
printf("%s server start to listen port %d\n", argv[0],serv_port);
for ( ; ; )
{
/*
* The accept() system call is used with connection-based socket types (SOCK_STREAM, SOCK_SEQPACKET).
* It extracts the first connection request on the queue of pending connections for the listening
* socket linstenfd, creates a new connected socket(connfd), and returns a new file descriptor referring
* to that socket. The newly created socket is not in the listening state. The original socket
* listenfd is unaffected by this call.
*/
if( (connfd=accept(listenfd, (struct sockaddr *)NULL, NULL)) > 0)
{
ticks = time(NULL); /* Get current system time */
snprintf(send_buf, sizeof(send_buf), "%.24s\r\n", ctime(&ticks));
if(write(connfd, send_buf, strlen(send_buf)) < 0)
{
printf("Write current time to client failure: %s\n", strerror(errno));
}
close(connfd);
}
}
CleanUp:
close(listenfd); /* We must close socket File Description when program exit*/
return 0;
}
复制代码
在我们的ARM开发板上跑的客户端程序:
/*********************************************************************************
* Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com>
* All rights reserved.* Thanks To: W. Richard Stevens, who bring me to the Linux program world!
*
* Filename: socket_client.c
* Description: This is a sample socket client demo program.
*
* Version: 1.0.0(06/08/2012~)
* Author: Guo Wenxue <guowenxue@gmail.com>
* ChangeLog: 1, Release initial version on "06/08/2012 02:50:51 PM"
*
********************************************************************************/
/* Some Unix Program Standard head file */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* Socket Program head file */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> /* sockaddr_in{} and other Internet define */
#include <errno.h> /* strerror(), perror(), errno head file*/
#include <arpa/inet.h> /* For inet_pton() */
#define DAYTIME_SERV_PORT 8888
#define MAX_BUF_SIZE 1024
/* Argc is the program linux running command arguments count, and argv is
* the arguments string value. All of the arguments take as string.
* For example:
* If we run this program as "./socket_client 192.168.3.15", there are two
* arguments, so argc=2, argv[0] is the first argument, which is string value
* "./socket_client" and argv[1] is the second argment, which is string value
* "1921.68.3.15".
*/
int main(int argc, char **argv)
{
int sockfd, len, retval;
char recv_buf[MAX_BUF_SIZE];
struct sockaddr_in servaddr;
/* Check the arguments count, if No serverip address give as an argument,
* then program exit */
if(2 != argc)
{
printf("usage: %s <ServerIPaddress>\n", argv[0]);
printf("Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com>\n");
return -1;
}
/* Open an IPV4(AF_INET) TCP(SOCK_STREAM) Socket File Description, UDP socket should
* use SOCK_DGRAM,We can use linux command "man socket" to see this function manual
*/
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
/* strerror() is the 1st way to display the failure reason, argument
* errno is a globle variable defined in <errno.h>, we can use linux command
* "man strerror" to see this function manual*/
printf("Use socket() to create a TCP socket failure: %s\n", strerror(errno));
return -1;
}
/* Now we set the Server Information, include IPV4 or IPV6, Server Port, Server IP address */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET; /* Set it as IPV4 protocal */
servaddr.sin_port = htons(DAYTIME_SERV_PORT); /* Daytime server port*/
/* argv[1] we take as Server IP address, it's the second arguments in running command */
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
{
printf("Use inet_pton() to set the Server IP address failure.\n");
retval = -2;
goto CleanUp;
}
/* Now call connect() function to connect to the server, we can use linux command "man connect"
* to see this function manual */
printf("Connect to Server [%s:%d]\n", argv[1], DAYTIME_SERV_PORT);
if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
{
printf("Connect to the server [%s:%d] failure\n", argv[1], DAYTIME_SERV_PORT);
retval = -3;
goto CleanUp;
}
/* Once we connect to the server successfully, we can receive the data from the socket socekt */
while ( (len = read(sockfd, recv_buf, MAX_BUF_SIZE)) > 0)
{
recv_buf[len] = 0; /* null terminate */
printf("Get Time from server %s: %s\n", argv[1], recv_buf);
}
if( len < 0 )
{
/* perror() ss the 2nd way to display the failure reason */
perror("Read() from socket failure");
retval = -4;
goto CleanUp;
}
CleanUp:
close(sockfd); /* We must close socket File Description when program exit*/
return 0;
}
复制代码
源代码有了,我们开始编译,这里给了file和strip两个很有用的命令的用法:
让server端的程序在PC Linux上跑
[guowenxue@centos6 unp]$ gcc -static
socket_server.c -o socket_server
[guowenxue@centos6 unp]$ file socket_server
socket_server: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.18, not stripped
[guowenxue@centos6 unp]$ du -h socket_server
760K socket_server
[guowenxue@centos6 unp]$
[guowenxue@centos6 unp]$ file socket_server
socket_server: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.18, stripped
[guowenxue@centos6 unp]$ strip socket_server
[guowenxue@centos6 unp]$ du -h socket_server
688K socket_server
其实嵌入式应用程序开发,就是写完代码后的一个交叉编译的过程。那什么是交叉编译呢?简单的来说,就是用交叉编译器编译出来的程序,在另外一个处理器(如我们的ARM)上跑,而不是在本地处理器(如我们的X86)上跑。那怎么知道我们编译的程序是在X86上跑,还是在ARM平台上跑呢?那就好好研究一下file命令的输出。下面我们开始交叉编译client端程序:
[guowenxue@centos6 unp]$ /opt/buildroot-2011.11/arm926t/usr/bin/arm-linux-gcc socket_client.c -o socket_client.c
喜欢使用TAB键补齐命令的童鞋们,估计会经常碰到我上面这条悲摧的命令。如果你没碰到,够勇敢的话,可以试试。上面的命令会把编译生成的可执行文件覆盖我们的C源码文件socket_client.c.
我们使用file命令看看他的信息:
[guowenxue@centos6 unp]$ file socket_client.c
socket_client.c: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
好在哥们使用git管着我的源代码,别跟我说你不知道git/svn是啥?21世纪不知道git/svn的程序不是好程序员,如果你还真不知道,那么西元200年孙策就告诉我们,“外事不决找google,内事不决问baidu”。
[guowenxue@centos6 unp]$ git checkout socket_client.c
[guowenxue@centos6 unp]$ file socket_client.c
socket_client.c: ASCII C program text
噢,在git的帮助下,我胡汉三又回来啦!言归正传,上面通过一个失误讲解了git的一个小作用。下面来正经的:
[guowenxue@centos6 unp]$ /opt/buildroot-2011.11/arm926t/usr/bin/arm-linux-gcc -static socket_client.c -o socket_client
[guowenxue@centos6 unp]$ file socket_client
socket_client: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, not stripped
[guowenxue@centos6 unp]$ du -h socket_client
124K socket_client
通过file命令,我们可以看到,socket_client是32位小端字节序(LSB)上的ELF格式的可执行程序,在ARM上跑,是静态编译的(statically linked),没有strip. 如果没有strip,文件的大小为124K.
下面我们使用strip命令给他剥掉华丽的外衣后再看看文件类型和大小:
[guowenxue@centos6 unp]$ /opt/buildroot-2011.11/arm926t/usr/bin/arm-linux-strip socket_client
[guowenxue@centos6 unp]$ file socket_client
socket_client: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, stripped
[guowenxue@centos6 unp]$ du -h socket_client
76K socket_client
是ARM的就该放到ARM上跑,是X86的,我们就应该在X86上运行。是火星上的,我们就把它扔到火星上去:
PC端上,首先把ARM上跑的socket_client放到我们的tftp服务器根目录下去:
[guowenxue@centos6 unp]$ cp socket_client /tftp/
别说,你不知道怎么在Linux上假设tftp服务器,那好好看看我的这个文章吧:
http://mcuos.com/thread-7115-1-1.html
然后在本地Linux服务器上开始运行我们的服务器端程序:
[guowenxue@centos6 unp]$ ./socket_server
Another Usage: ./socket_server [ServerPort]
./socket_server server start to listen port 8888
完成PC端的工作,我们就要跑到ARM这颗火星上来处理client端了:
ARM上跑的是Linux,用的当时最新的3.3,不过现在已经out啦!
~ >: uname -a
Linux CoherentPlus 3.3.0 #1 Thu May 3 16:45:19 CST 2012 armv5tejl GNU/Linux
首先使用tftp命令下载我们的刚才编译出来的程序,192.168.1.78是我的Linux服务器IP地址,他开启了tftp服务,tftp服务的根目录是/tftp.
~ >: tftp -gr socket_client 192.168.1.78
socket_client 100% |***********************************************************************************| 77112 0:00:00 ETA
既然是Linux,运行之前,肯定要给他执行的权限咯。
~ >: chmod 777 socket_client
火星人开始跟地球人聊天了:“地球上的兄弟,把你们当前的时间告诉我吧!”
地球上的兄弟很爽快的答应:“哥们,我们现在的时间是Fri Jun 8 17:47:04 2012,欢迎光临!”
~ >: ./socket_client
usage: ./socket_client <ServerIPaddress>
Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com>
~ >: ./socket_client 192.168.1.78
Connect to Server [192.168.1.78:8888]
Get Time from server 192.168.1.78: Fri Jun 8 17:47:04 2012
~ >:
相关文章推荐
- 语音助手、聊天机器人何时才能像真人一样跟我们对话?
- 我们一起学习WCF 第九篇聊天功能
- 情侣从恋爱到分手的聊天截图:我们曾爱过,想到就最心酸
- 刚才偶的ARM开发板技术支持群的群友讨论了人生,推荐我们看《穷爸爸,富爸爸》这本书,看了一下,的确值得推荐!
- 我们的聊天!
- 前台页面jsp调用qq发起聊天,点击“联系我们”链接弹窗qq聊天窗口
- 生命呀,求其在这玩深沉。表面上不和我们聊天
- 安卓游戏盗取用户 WhatsApp 聊天记录 带给我们的思考!
- 当我跟妹子聊天,我们在聊什么
- QQ聊天记录存储方式
- 请给我们一个“中国梦
- iPhone开发:类似iChat的聊天泡泡
- Mate 桌面系统下Gnome Keyring 被锁定,并且我们处于非交互方式
- 【english】当我们谈论英语的时候我们在谈论什么
- 给自己的网站加入智能聊天功能
- 我们扯平了吗
- 我们为什么要结对编程?(why we choose pair programming)
- WCF也可以做聊天程序
- 我们真的需要软件工程吗?
- 用 JSQMessagesViewController 创建一个 iOS 聊天 App - 第 3 部分