嵌入式Linux网络编程

时间:2020-12-15 19:20:19

嵌入式Linux网络编程

分类: 嵌入式学习 95人阅读 评论(2) 收藏 举报


             TCP:Transmission Control Protocol 传输控制协议TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议。

OSI 协议参考模型,它是基于国际标准化组织(ISO)的建议发展起来的,从上到下共分为7 层:应用层、表示层、会话层、传输层、网络层、数据链路层及物理层

TCP/IP 参考模型  :从上到下共分为4 层  :应用层、传输层、网络层、网络接口层

TCP:为应用程序提供可靠的通信连接。适合于一次传输大批数据的情况。并适用于要求得到响应的应用程序。
UDP:提供了无连接通信,且不对传送包进行可靠的保证。适合于一次传输少量数据,可靠性则由应用层来负责。

TCP 三次握手协议
TCP对话通过三次握手来初始化的。三次握手的目的是使数据段的发送和接收同步,告诉其他主机其一次可接收的数据量,并建立虚连接。

三次握手的简单过程。
· 初始化主机通过一个同步标志置位的数据段发出会话请求。
· 接收主机通过发回具有以下项目的数据段表示回复:同步标志置位、即将发送的数据段的起始字节的顺序号、应答并带有将收到的下一个数据段的字节顺序号。
· 请求主机再回送一个数据段,并带有确认顺序号和确认号。

UDP

UDP 即用户数据报协议,它是一种无连接协议,因此不需要像TCP 那样通过三次握手来建立一个连接。同时,一个UDP应用可同时作为应用的客户或服务器方。由于UDP协议
并不需要建立一个明确的连接,因此建立UDP应用要比建立TCP应用简单得多。

socket

socket接口是一种特殊的I/O,它也是一种文件描述符。每一个socket都用一个半相关描述{协议,本地地址、本地端口}来表示;一个完整的套接字则用一个相关描述{协议,本地地址、本地端口、远程地址、远程端口}

socket有3 种类型
(1)流式socket(SOCK_STREAM)
流式套接字提供可靠的、面向连接的通信流;它使用TCP协议,从而保证了数据传输的正确性和顺序性。
(2)数据报socket(SOCK_DGRAM)
数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证是可靠、无差错的。它使用数据报协议UDP。
(3)原始socket
原始套接字允许对底层协议如IP或ICMP进行直接访问,它功能强大但使用较为不便,主要用于一些协议的开发。

地址结构相关处理

   1 . 下面首先介绍两个重要的数据类型:sockaddr 和sockaddr_in,这两个结构类型都是用来保存socket信息的,如下所示:

  1. struct sockaddr {  
  2. unsigned short sa_family; /*地址族*/  
  3. char sa_data[14]; /*14字节的协议地址,包含该socket的IP地址和端口号。*/  
  4. };  
  5. struct sockaddr_in {  
  6. short int sa_family; /*地址族*/  
  7. unsigned short int sin_port; /*端口号*/  
  8. struct in_addr sin_addr; /*IP地址*/  
  9. unsigned char sin_zero[8]; /*填充0 以保持与struct sockaddr同样大小*/  
  10. };  

    这两个数据类型是等效的,可以相互转化,通常sockaddr_in数据类型使用更为方便。在建立socketadd或sockaddr_in后,就可以对该socket 进行适当的操作了。

  2.结构字段

     下面列出了该结构sa_family字段可选的常见值。

结构定义头文件#include <netinet/in.h>
AF_INET:IPv4协议
AF_INET6:IPv6协议
AF_LOCAL:UNIX域协议
AF_LINK:链路地址协议
Sa_family
AF_KEY:密钥套接字(socket)

htons、ntohs、htonl、ntohl。这四个地址分别实现网络字节序和主机字节序的转化,这里的h 代表host,n 代表network,s 代表short,l 代表long

3.地址格式转化函数

          在IPv4 中用到的函数有inet_aton、inet_addr 和inet_ntoa,而IPv4 和IPv6 兼容的函数有inet_pton 和inet_ntop。在IPv4 中用到的函数有inet_aton、inet_addr 和inet_ntoa,而IPv4 和IPv6 兼容的函数有inet_pton 和inet_ntop。

      inet_pton 函数是将点分十进制地址映射为二进制地址,而inet_ntop 是将二进制地址映射为点分十进制地址。

     函数原型如下:

         int inet_pton(int family,const char *strptr, void *addrptr)  strptr:要转化的值   addrptr:转化后的地址

         int inet_ntop(int family, void *addrptr, char *strptr, size_t len)     addrptr:转化后的地址  strptr:要转化的值 

4.名字地址转化

               一些函数可以实现主机名和地址的转化,最为常见的有gethostbyname、gethostbyaddr、getaddrinfo等

              gethostbyname 是将主机名转化为IP 地址,gethostbyaddr 则是逆操作,是将IP地址转化为主机名,另外getaddrinfo还能实现自动识别IPv4地址和IPv6地址。

            gethostbyname和gethostbyaddr 都涉及到一个hostent 的结构体

  1. Struct hostent{  
  2. char *h_name;/*正式主机名*/  
  3. char **h_aliases;/*主机别名*/  
  4. int h_addrtype;/*地址类型*/  
  5. int h_length;/*地址长度*/  
  6. char **h_addr_list;/*指向IPv4或IPv6的地址指针数组*/  
  7. }  

      调用该函数后就能返回hostent 结构体的相关信息。
     

  1. struct addrinfo{  
  2. int ai_flags;/*AI_PASSIVE,AI_CANONNAME;*/  
  3. int ai_family;/*地址族*/  
  4. int ai_socktype;/*socket类型*/  
  5. int ai_protocol;/*协议类型*/  
  6. size_t ai_addrlen;/*地址长度*/  
  7. char *ai_canoname;/*主机名*/  
  8. struct sockaddr *ai_addr;/*socket结构体*/  
  9. struct addrinfo *ai_next;/*下一个指针链表*/  
  10. }  


    getaddrinfo函数涉及到一个addrinfo的结构体

头文件:           #include <netdb.h>
函数原型

           Struct hostent *gethostbyname(const char *hostname)      Hostname:主机名

            Int getaddrinfo(const char *hostname,const char *service,const struct addrinfo*hints,struct addrinfo **result)    service:服务名或十进制的串口号字符串   hints:服务线索   result:返回结果

 -----------    socket基础编程

socket编程的基本函数有socket、bind、listen、accept、send、sendto、recv、recvfrom这几个

· socket:该函数用于建立一个socket连接,可指定socket类型等信息。在建立了socket连接之后,可对socketadd或sockaddr_in进行初始化,以保存所建立的socket信息。
· bind:该函数是用于将本地IP 地址绑定端口号的,若绑定其他地址则不能成功。另外,它主要用于TCP的连接,而在UDP的连接中则无必要。
· connect:该函数在TCP中是用于bind的之后的client 端,用于与服务器端建立连接,而在UDP中由于没有了bind函数,因此用connect有点类似bind函数的作用。
· send和recv:这两个函数用于接收和发送数据,可以用在TCP中,也可以用在UDP中。当用在UDP时,可以在connect函数建立连接之后再用。
· sendto和recvfrom:这两个函数的作用与send和recv函数类型,也可以用在TCP和UDP中。当用在TCP时,后面的几个与地址有关参数不起作用,函数作用等同于send和recv;当用在UDP时,可以用在之前没有使用connect的情况时,这两个函数可以自动寻找制定地址并进行连接。

用TCP协议socket编程流程图

嵌入式Linux网络编程

用UDP协议socket编程流程图

嵌入式Linux网络编程

函数格式

所需头文件#include <sys/socket.h>
函数原型int socket(int family, int type, int protocol)    

          family:协议族  type:套接字类型:SOCK_STREAM:字节流套接字socket   SOCK_DGRAM:数据报套接字socket  SOCK_RAW:原始套接字socket

函数原型int bind(int sockfd,struct sockaddr *my_addr, int addrlen)    socktd:套接字描述符 my_addr:本地地址  addrlen:地址长度

函数原型int listen(int sockfd, int backlog)    Backlog:请求队列中允许的最大请求数,大多数系统缺省值为20

函数原型int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)    addr:客户端地址  addrlen:地址长度

函数原型int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)  serv_addr:服务器端地址  addrlen:地址长度

函数原型int send(int sockfd, const void *msg, int len, int flags)  msg:指向要发送数据的指针  len:数据长度   flags:一般为0

函数原型int recv(int sockfd,void *buf,int len,unsigned int flags)

函数原型int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr*to, int tolen)

函数原型int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int*fromlen)  from:源机的IP地址和端口号信息  tolen:地址长度

 

一个简单的C/S例子

server.c

  1. #include <sys/types.h>   
  2. #include <sys/socket.h>   
  3. #include <stdio.h>   
  4. #include <stdlib.h>   
  5. #include <errno.h>   
  6. #include <string.h>   
  7. #include <unistd.h>   
  8. #include <netinet/in.h>   
  9. #define SERVPORT 3333   
  10. #define BACKLOG 10   
  11. #define MAX_CONNECTED_NO 10   
  12. #define MAXDATASIZE 5   
  13. int main()  
  14. {  
  15. struct sockaddr_in server_sockaddr,client_sockaddr;  
  16. int sin_size,recvbytes;  
  17. int sockfd,client_fd;  
  18. char buf[MAXDATASIZE];  
  19. /*建立socket连接*/  
  20. if((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1){  
  21. perror("socket");  
  22. exit(1);  
  23. }  
  24. printf("socket success!,sockfd=%d\n",sockfd);  
  25. /*设置sockaddr_in 结构体中相关参数*/  
  26. server_sockaddr.sin_family=AF_INET;  
  27. server_sockaddr.sin_port=htons(SERVPORT);  
  28. server_sockaddr.sin_addr.s_addr=INADDR_ANY;  
  29. bzero(&(server_sockaddr.sin_zero),8);  
  30. /*绑定函数bind*/  
  31. if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct  
  32. sockaddr))== -1){  
  33. perror("bind");  
  34. exit(1);  
  35. }  
  36. printf("bind success!\n");  
  37. /*调用listen函数*/  
  38. if(listen(sockfd,BACKLOG)== -1){  
  39. perror("listen");  
  40. exit(1);  
  41. }  
  42. printf("listening....\n");  
  43. /*调用accept函数,等待客户端的连接*/  
  44. if((client_fd=accept(sockfd,(struct sockaddr *)&client_sockaddr,&sin_  
  45. size))== -1){  
  46. perror("accept");  
  47. exit(1);  
  48. }  
  49. /*调用recv函数接收客户端的请求*/  
  50. if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))== -1){  
  51. perror("recv");  
  52. exit(1);  
  53. }  
  54. printf("received a connection :%s\n",buf);  
  55. close(sockfd);  
  56. }  

client.c

  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. #include <errno.h>   
  4. #include <string.h>   
  5. #include <netdb.h>   
  6. #include <sys/types.h>   
  7. #include <netinet/in.h>   
  8. #include <sys/socket.h>   
  9. #define SERVPORT 3333   
  10. #define MAXDATASIZE 100   
  11. main(int argc,char *argv[]){  
  12. int sockfd,sendbytes;  
  13. char buf[MAXDATASIZE];  
  14. struct hostent *host;  
  15. struct sockaddr_in serv_addr;  
  16. if(argc < 2){  
  17. fprintf(stderr,"Please enter the server's hostname!\n");  
  18. exit(1);  
  19. }  
  20. /*地址解析函数*/  
  21. if((host=gethostbyname(argv[1]))==NULL){  
  22. perror("gethostbyname");  
  23. exit(1);  
  24. }  
  25. /*创建socket*/  
  26. if((sockfd=socket(AF_INET,SOCK_STREAM,0))== -1){  
  27. perror("socket");  
  28. exit(1);  
  29. }  
  30. /*设置sockaddr_in 结构体中相关参数*/  
  31. serv_addr.sin_family=AF_INET;  
  32. serv_addr.sin_port=htons(SERVPORT);  
  33. serv_addr.sin_addr=*((struct in_addr *)host->h_addr);  
  34. bzero(&(serv_addr.sin_zero),8);  
  35. /*调用connect函数主动发起对服务器端的连接*/  
  36. if(connect(sockfd,(struct sockaddr *)&serv_addr,\  
  37. sizeof(struct sockaddr))== -1){  
  38. perror("connect");  
  39. exit(1);  
  40. }  
  41. /*发送消息给服务器端*/  
  42. if((sendbytes=send(sockfd,"hello",5,0))== -1){  
  43. perror("send");  
  44. exit(1);  
  45. }  
  46. close(sockfd);  
  47. }  




网络高级编程网络高级编程所需头文件   #include <sys/socket.h>
函数原型int socket(int family, int type, int protocol)所需头文件#include <sys/socket.h>
函数原型int socket(int family, int type, int protocol)所需头文件#include <sys/socket.h>
函数原型int socket(int family, int type, int protocol)调用该函数后就能返回hostent 结构体的相关信息。
getaddrinfo函数涉及到一个addrinfo的结构体调用该函数后就能返回hostent 结构体的相关信息。
getaddrinfo函数涉及到一个addrinfo的结构体

5.网络高级编程

    之前介绍的如connet、recv、send都是阻塞性函数,若资源没有准备好,则调用该函数的进程将进入睡眠状态,这样就无法处理I/O 多路复用的情况了,fcntl和select是了两种解决I/O 多路复用的解决方法

1.fcntl
函数fcntl针对socket编程提供了如下的编程特性。
· 非阻塞I/O:可将cmd设置为F_SETFL,将lock设置为O_NONBLOCK。
· 信号驱动I/O:可将cmd设置为F_SETFL,将lock设置为O_ASYNC。

简单的例子fcntl.c

  1. #include <sys/types.h>   
  2. #include <sys/socket.h>   
  3. #include <sys/wait.h>   
  4. #include <stdio.h>   
  5. #include <stdlib.h>   
  6. #include <errno.h>   
  7. #include <string.h>   
  8. #include <sys/un.h>   
  9. #include <sys/time.h>   
  10. #include <sys/ioctl.h>   
  11. #include <unistd.h>   
  12. #include <netinet/in.h>   
  13. #include <fcntl.h>   
  14. #define SERVPORT 3333   
  15. #define BACKLOG 10   
  16. #define MAX_CONNECTED_NO 10   
  17. #define MAXDATASIZE 100   
  18. int main()  
  19. {  
  20. struct sockaddr_in server_sockaddr,client_sockaddr;  
  21. int sin_size,recvbytes,flags;  
  22. int sockfd,client_fd;  
  23. char buf[MAXDATASIZE];  
  24. if((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1){  
  25. perror("socket");  
  26. exit(1);  
  27. }  
  28. printf("socket success!,sockfd=%d\n",sockfd);  
  29. server_sockaddr.sin_family=AF_INET;  
  30. server_sockaddr.sin_port=htons(SERVPORT);  
  31. server_sockaddr.sin_addr.s_addr=INADDR_ANY;  
  32. bzero(&(server_sockaddr.sin_zero),8);  
  33. if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct  
  34. sockaddr))== -1){  
  35. perror("bind");  
  36. exit(1);  
  37. }  
  38. printf("bind success!\n");  
  39. if(listen(sockfd,BACKLOG)== -1){  
  40. perror("listen");  
  41. exit(1);  
  42. }  
  43. printf("listening....\n");  
  44. /*调用fcntl函数设置非阻塞参数*/  
  45. if((flags=fcntl( sockfd, F_SETFL, 0))<0)  
  46. perror("fcntl F_SETFL");  
  47. flag |= O_NONBLOCK;  
  48. if(fcntl(fd,F_SETEL,flags)<0)  
  49. perror("fcntl");  
  50. while(1){  
  51. sin_size=sizeof(struct sockaddr_in);  
  52. if((client_fd=accept(sockfd,(structsockaddr*)&client_sockaddr,  
  53. &sin_size))== -1){  
  54. perror("accept");  
  55. exit(1);  
  56. }  
  57. if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))== -1){  
  58. perror("recv");  
  59. exit(1);  
  60. }  
  61. if(read(client_fd,buf,MAXDATASIZE)<0){  
  62. perror("read");  
  63. exit(1);  
  64. }  
  65. printf("received a connection :%s",buf);  
  66. close(client_fd);  
  67. exit(1);  
  68. }/*while*/  
  69. }  

2.select
使用fcntl 函数虽然可以实现非阻塞I/O 或信号驱动I/O,但在实际使用时往往会对资源是否准备完毕进行循环测试,这样就大大增加了不必要的CPU 资源。select函数还可以设置等待的时

select_socket.c

 

  1. #include <sys/types.h>   
  2. #include <sys/socket.h>   
  3. #include <sys/wait.h>   
  4. #include <stdio.h>   
  5. #include <stdlib.h>   
  6. #include <errno.h>   
  7. #include <string.h>   
  8. #include <sys/un.h>   
  9. #include <sys/time.h>   
  10. #include <sys/ioctl.h>   
  11. #include <unistd.h>   
  12. #include <netinet/in.h>   
  13. #define SERVPORT 3333   
  14. #define BACKLOG 10   
  15. #define MAX_CONNECTED_NO 10   
  16. #define MAXDATASIZE 100   
  17. int main()  
  18. {  
  19. struct sockaddr_in server_sockaddr,client_sockaddr;  
  20. int sin_size,recvbytes;  
  21. fd_set readfd;  
  22. fd_set writefd;  
  23. int sockfd,client_fd;  
  24. char buf[MAXDATASIZE];  
  25. if((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1){  
  26. perror("socket");  
  27. exit(1);  
  28. }  
  29. printf("socket success!,sockfd=%d\n",sockfd);  
  30. server_sockaddr.sin_family=AF_INET;  
  31. server_sockaddr.sin_port=htons(SERVPORT);  
  32. server_sockaddr.sin_addr.s_addr=INADDR_ANY;  
  33. bzero(&(server_sockaddr.sin_zero),8);  
  34. if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct  
  35. sockaddr))== -1){  
  36. perror("bind");  
  37. exit(1);  
  38. }  
  39. printf("bind success!\n");  
  40. if(listen(sockfd,BACKLOG)== -1){  
  41. perror("listen");  
  42. exit(1);  
  43. }  
  44. printf("listening....\n");  
  45. /*将调用socket函数的描述符作为文件描述符*/  
  46. FD_ZERO(&readfd);  
  47. FD_SET(sockfd,&readfd);  
  48. while(1){  
  49. sin_size=sizeof(struct sockaddr_in);  
  50. /*调用select函数*/  
  51. if(select(MAX_CONNECTED_NO,&readfd,NULL,NULL,(struct timeval *)0)>0){  
  52. if(FD_ISSET(sockfd,&readfd)>0){  
  53. if((client_fd=accept(sockfd,(struct sockaddr *)&client_  
  54. sockaddr,&sin_size))== -1){  
  55. perror("accept");  
  56. exit(1);  
  57. }  
  58. if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))== -1){  
  59. perror("recv");  
  60. exit(1);  
  61. }  
  62. if(read(client_fd,buf,MAXDATASIZE)<0){  
  63. perror("read");  
  64. exit(1);  
  65. }  
  66. printf("received a connection :%s",buf);  
  67. }/*if*/  
  68. close(client_fd);  
  69. }/*select*/  
  70. }/*while*/  
  71. }  


 

下面是实现简单的linux 下的TCP通讯程序

服务器端的代码如下:

server.c

  1. <P>#include<stdio.h>  
  2. #include<stdlib.h>   
  3. #include<errno.h>   
  4. #include<string.h>   
  5. #include<sys/types.h>   
  6. #include<netinet/in.h>   
  7. #include<sys/socket.h>   
  8. #include<sys/wait.h>   
  9. #include<pthread.h></P><P>#define MYPORT 3490   
  10. #define BACKLOG 10    
  11. #define MAXDATASIZE 1024</P><P>int sockfd,new_fd;   
  12. pthread_t  accthread,recthread;</P><P>void recmessage(void){  
  13.     while(1){  
  14.       int numbytes;  
  15.       char buf[MAXDATASIZE];  
  16.       if((numbytes = recv(new_fd,buf,MAXDATASIZE,0)) == -1){  
  17. perror("recv");  
  18.    exit(1);  
  19.      }  
  20.       buf[numbytes] = '\0';  
  21.   if(strcmp(buf,"exit") == 0){  
  22.  printf("Client is closed\n");  
  23.  close(new_fd);  
  24.  close(sockfd);  
  25.  exit(1);  
  26. }  
  27.  printf("Client:%s\n",buf);  
  28.   }  
  29. }</P><P>  
  30. void acceptconnect(void){  
  31.  struct sockaddr_in their_addr;  
  32.  int sin_size;  
  33.  sin_size = sizeof(struct sockaddr_in);  
  34.  if((new_fd = accept(sockfd,(struct sockaddr*)&their_addr,&sin_size)) == -1){  
  35.     perror("accept");  
  36.     exit(1);  
  37.    }  
  38.   printf("server:got connection from %s\n",inet_ntoa(their_addr.sin_addr));  
  39.    
  40.  if((pthread_create(&recthread,NULL,(void *)recmessage,NULL))!= 0){  
  41.     printf("Create thread error!\r\n");  
  42.     exit(1);  
  43.   }  
  44. }  
  45. int main(void){  
  46.  struct sockaddr_in my_addr;  
  47.  if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){  
  48.    perror("socket");  
  49.    exit(1);  
  50.   }  
  51.   my_addr.sin_family = AF_INET;  
  52.   my_addr.sin_port = htons(MYPORT);  
  53.   my_addr.sin_addr.s_addr = INADDR_ANY;  
  54.   bzero(&(my_addr.sin_zero),8);  
  55.   if(bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr)) == -1){  
  56.    perror("bind");  
  57.    exit(1);  
  58.    }  
  59.    if(listen(sockfd,BACKLOG) == -1){  
  60.     perror("listen");  
  61.     exit(1);  
  62.    }  
  63.    if((pthread_create(&accthread,NULL,(void *)acceptconnect,NULL)) != 0){  
  64.     printf("Create thread error!\r\n");  
  65.     exit(1);  
  66.    }  
  67.   while(1){  
  68.   char msg[MAXDATASIZE];  
  69.     
  70.   scanf("%s",msg);  
  71.   if(send(new_fd,msg,strlen(msg),0) == -1){  
  72.    perror("send");  
  73.    close(new_fd);  
  74.    exit(1);  
  75.   }  
  76.   if(strcmp(msg,"exit") == 0){  
  77.    printf("Byebye!\n");  
  78.    close(new_fd);  
  79.    close(sockfd);  
  80.    exit(1);  
  81.   }  
  82.  }  
  83.   return 0;  
  84. }  
  85. </P>  

客户端的代码

client.c

  1. #include<stdio.h>   
  2. #include<stdlib.h>   
  3. #include<errno.h>   
  4. #include<string.h>   
  5. #include<netdb.h>   
  6. #include<sys/types.h>   
  7. #include<netinet/in.h>   
  8. #include<sys/socket.h>   
  9. #include<pthread.h>   
  10.   
  11. #define PORT 3490   
  12. #define MAXDATASIZE 1024   
  13. int sockfd;  
  14. pthread_t recthread;  
  15.   
  16. void recmessage(void){  
  17.   while(1){  
  18.     int numbytes;  
  19.     char buf[MAXDATASIZE];  
  20.       
  21.     if((numbytes = recv(sockfd,buf,MAXDATASIZE,0)) == -1){  
  22.      perror("recv");  
  23.      exit(1);  
  24.      }  
  25.     buf[numbytes]='\0';  
  26.    if(strcmp(buf,"exit") == 0){  
  27.     printf("Server is closed\n");  
  28.     close(sockfd);  
  29.     exit(1);  
  30.     }  
  31.     printf("Server:%s\n",buf);  
  32.    }  
  33. }  
  34.   
  35. int main(int argc,char *argv[]){  
  36.   struct hostent *host;  
  37.   struct sockaddr_in their_addr;  
  38.   if(argc != 2){  
  39.    fprintf(stderr,"usage:client hostname\n");  
  40.    exit(1);  
  41.   }  
  42.     /* 使用hostname查询host 名字 */  
  43.   if((host=gethostbyname(argv[1])) == NULL){  
  44.    herror("gethostbyname");  
  45.    exit(1);  
  46.   }  
  47. // AF_INET:Internet;SOCK_STREAM:TCP   
  48. /* 客户程序开始建立 sockfd描述符 */   
  49.   if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){  
  50.    perror("socket");  
  51.    exit(1);  
  52.    }  
  53.      
  54. // 初始化,置0   
  55. bzero(&(their_addr.sin_zero),8);  
  56. // IPV4   
  57.   their_addr.sin_family = AF_INET;  
  58.  // (将本机器上的short数据转化为网络上的short数据)端口号   
  59.   their_addr.sin_port = htons(PORT);  
  60. // IP地址   
  61.   their_addr.sin_addr = *((struct in_addr *)host->h_addr);  
  62.   /* 客户程序发起连接请求 */   
  63.   if(connect(sockfd,(struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1){  
  64.    perror("connect");  
  65.    exit(1);  
  66.   }  
  67. /* 连接成功了 */   
  68.     printf("connect sucess!!!:\n");  
  69.   if((pthread_create(&recthread,NULL,(void *)recmessage,NULL))!=0){  
  70.     printf("Create thread error!\r\n");  
  71.    exit(1);  
  72.   }  
  73.   while(1){  
  74.   char msg[MAXDATASIZE];  
  75.   scanf("%s",msg);  
  76.   if(send(sockfd,msg,strlen(msg),0) == -1){  
  77.    perror("send");  
  78.    close(sockfd);  
  79.    exit(1);  
  80.    }  
  81.   if(strcmp(msg,"exit") == 0){  
  82.    printf("Byebye!\n");  
  83. /* 结束通讯 */   
  84.    close(sockfd);  
  85.    exit(1);  
  86.   }  
  87. }  
  88.   return 0;  
  89.   }  

 

在终端下输入的命令:  gcc server.c  -lpthread -o  server  

                                      ./server

打开新的终端输入命令: gcc client.c -lpthread -o  client

                                          ./client   127.0.0.1(要通信的IP地址,这里用的是网络的虚拟IP地址)

然后呢,还有一个SDL版本的图形界面

clientsdl.c

  1. #include<stdlib.h>  
  2. #include "SDL/SDL.h"  
  3. #include<stdio.h>  
  4. #include<errno.h>  
  5. #include<string.h>  
  6. #include<netdb.h>  
  7. #include<sys/types.h>  
  8. #include<netinet/in.h>  
  9. #include<sys/socket.h>  
  10. #include<pthread.h>  
  11. #define PORT 3490  
  12. #define MAXDATASIZE 1024  
  13.   
  14. int sockfd;  
  15. pthread_t recthread;  
  16.   
  17. SDL_Surface * screen;  
  18. SDL_Surface * image;  
  19. SDL_Event event;  
  20.   
  21.   
  22. int drawsreen();  
  23. int init_SDL();  
  24. int event_test();  
  25.   
  26. void recmessage(void){  
  27.   while(1){  
  28.    static int i=5;  
  29.     int numbytes;  
  30.     char buf[MAXDATASIZE];  
  31.       
  32.     if((numbytes = recv(sockfd,buf,MAXDATASIZE,0)) == -1){  
  33.  perror("recv");       
  34.      exit(1);  
  35.      }  
  36.     buf[numbytes]='\0';  
  37.    if(strcmp(buf,"exit") == 0){  
  38. printf("Server is closed\n");    close(sockfd);  
  39.     exit(1);  
  40.     }  
  41.      i=i+10;  
  42. printf("鏈嶅姟鍣ㄧ璇?%s\n",buf);  
  43.   
  44.     if(i>300){  
  45. drawsreen();  
  46. i=0;  
  47. stringColor(screen, 40, i, "server said:\t\t", 0x000000FF);  
  48. stringColor(screen, 200, i, buf, 0xFFFFFF);  
  49. SDL_UpdateRect(screen, 0, 0,0,0);  
  50. }else{  
  51. stringColor(screen, 40, i, "server said:\t\t", 0x000000FF);  
  52. stringColor(screen, 200, i, buf, 0xFFFFFF);  
  53. SDL_UpdateRect(screen, 0, 0,0,0);  
  54. }  
  55.   
  56.    }  
  57. }  
  58. int main(int argc,char *argv[]){  
  59.   
  60. init_SDL();  
  61. drawsreen();  
  62.   
  63.   struct hostent *host;  
  64.   struct sockaddr_in their_addr;  
  65.   if(argc != 2){  
  66.    fprintf(stderr,"璇疯緭鍏ュ鎴风殑IP鍦板潃\n");  
  67.    
  68. stringColor(screen, 40, 0, "please input the client address!!\n",0x000000FF);  
  69.    exit(1);  
  70.   }  
  71.     /* 浣跨敤hostname鏌ヨhost 鍚嶅瓧 */  
  72.   if((host=gethostbyname(argv[1])) == NULL){  
  73.    herror("娌℃湁鏌ュ埌鐩稿搴旂殑涓绘満鍚嶏紒\n");  
  74.    exit(1);  
  75.   }  
  76. // AF_INET:Internet;SOCK_STREAM:TCP  
  77. /* 瀹㈡埛绋嬪簭寮€濮嬪缓绔?sockfd鎻忚堪绗?*/   
  78.   if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){  
  79.    perror("socket閫氫俊鍑虹幇寮傚父锛侊紒");  
  80.    exit(1);  
  81.    }  
  82.      
  83. // 鍒濆鍖?缃?  
  84. bzero(&(their_addr.sin_zero),8);  
  85. // IPV4  
  86.   their_addr.sin_family = AF_INET;  
  87.  // (灏嗘湰鏈哄櫒涓婄殑short鏁版嵁杞寲涓虹綉缁滀笂鐨剆hort鏁版嵁)绔彛鍙?  
  88.   their_addr.sin_port = htons(PORT);  
  89. // IP鍦板潃  
  90.   their_addr.sin_addr = *((struct in_addr *)host->h_addr);  
  91.   /* 瀹㈡埛绋嬪簭鍙戣捣杩炴帴璇锋眰 */   
  92.   if(connect(sockfd,(struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1){  
  93.    perror("杩炴帴澶辫触锛侊紒");  
  94.    exit(1);  
  95.   }  
  96. SDL_UpdateRect(screen, 0, 0,0,0);  
  97. /* 杩炴帴鎴愬姛浜?*/   
  98.     printf("杩炴帴鎴愬姛!!!:\n");  
  99.   if((pthread_create(&recthread,NULL,(void *)recmessage,NULL))!=0){  
  100.     printf("鍒涘缓thread澶辫触!\r\n");  
  101.    exit(1);  
  102.   }  
  103.   while(1){  
  104.   char msg[MAXDATASIZE];  
  105.   scanf("%s",msg);  
  106.   if(send(sockfd,msg,strlen(msg),0) == -1){  
  107.    perror("鍙戦€佷俊鎭け璐ワ紒锛?);  
  108.    close(sockfd);  
  109.    exit(1);  
  110. SDL_UpdateRect(screen, 0, 0,0,0);  
  111.    }  
  112.   if(strcmp(msg,"exit") == 0){  
  113.    printf("Byebye!\n");  
  114. /* 缁撴潫閫氳 */   
  115.    close(sockfd);  
  116.    exit(1);  
  117.   }  
  118. }  
  119.   return 0;  
  120.           
  121.   
  122.           
  123. event_test();  
  124.   
  125. }  
  126.   
  127.   
  128. int drawsreen(){  
  129.   
  130.   
  131. image = SDL_LoadBMP("./bg.bmp");  
  132.   
  133.     if (image == NULL) {  
  134.         fprintf(stderr, "涓嶈兘涓嬭浇鍥剧墖, %s\n", SDL_GetError());  
  135.         return -1;  
  136.     }  
  137.   
  138.          if (SDL_BlitSurface(image, NULL, screen, NULL) < 0) {  
  139.         //瑙i噴涓€涓婲ULL锛岀涓€涓槸鎸夌収image鐨勫昂瀵告樉绀猴紝绗簩涓槸榛樿鏄剧ず   
  140.         fprintf(stderr, "BlitSurface error: %s\n", SDL_GetError());  
  141.         return -1;  
  142.     }  
  143.   
  144.   
  145. boxColor(screen, 10, 320,50, 360,0xff8f66);  
  146. boxColor(screen, 60, 320,100, 360,0xff8f66);  
  147. boxColor(screen, 110, 320,150, 360,0xff8f66);  
  148. boxColor(screen, 160, 320,200, 360,0xff8f66);  
  149. boxColor(screen, 210, 320,250, 360,0xff8f66);  
  150. boxColor(screen, 260, 320,300, 360,0xff8f66);  
  151. boxColor(screen, 310, 320,350, 360,0xff8f66);  
  152. boxColor(screen, 360, 320,400, 360,0xff8f66);  
  153. boxColor(screen, 410, 320,450, 360,0xff8f66);  
  154. boxColor(screen, 460, 320,500, 360,0xff8f66);  
  155.   
  156.   
  157.   
  158.   
  159.   
  160.   
  161.  stringColor(screen, 30, 340,"Q",0x000000FF);  
  162.  stringColor(screen, 80, 340,"W",0x000000FF);  
  163. stringColor(screen, 130, 340,"E",0x000000FF);  
  164.  stringColor(screen, 180, 340,"R",0x000000FF);  
  165. stringColor(screen, 230, 340,"T",0x000000FF);  
  166.  stringColor(screen, 280, 340,"Y",0x000000FF);  
  167. stringColor(screen, 330, 340,"U",0x000000FF);  
  168.  stringColor(screen, 380, 340,"I",0x000000FF);  
  169. stringColor(screen, 430, 340,"O",0x000000FF);  
  170.  stringColor(screen, 480, 340,"P",0x000000FF);  
  171.   
  172.   
  173.   
  174.   
  175.   
  176.   
  177.   
  178. SDL_UpdateRect(screen, 0, 0, 0, 0);  
  179.   
  180.   
  181.   
  182.   
  183.   
  184.   
  185. }  
  186. int init_SDL(){  
  187.   
  188.   
  189. //鍒濆鍖朣DL  
  190.     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) {  
  191.         fprintf(stderr, "init SDL %s\n", SDL_GetError());  
  192.         return -1;  
  193.     }  
  194.  atexit(SDL_Quit);  
  195.   
  196.   
  197.   
  198.   
  199. screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);  
  200.     if (screen == NULL) {  
  201.         fprintf(stderr, "涓嶈兘璁剧疆 640x480x8 video mode %s\n",SDL_GetError());  
  202.         return -1;  
  203.     }  
  204.  SDL_WM_SetCaption("TCP鑱婂ぉ绋嬪簭娴嬭瘯", NULL);  
  205.   
  206. }  
  207.   
  208.   
  209.    
  210.   
  211.   
  212. int event_test(){  
  213.   
  214.   
  215. while ( SDL_WaitEvent(&event) >= 0 ) {  
  216.         switch (event.type) {  
  217.                       
  218.             case SDL_MOUSEBUTTONDOWN:  
  219.   
  220.   
  221.                             printf("hello,world!!!");  
  222. SDL_UpdateRect(screen, 0, 0,0,0);  
  223. exit(0);  
  224. break;  
  225.   
  226.             case SDL_QUIT: {  
  227.   
  228.                 printf("Quit requested, quitting.\n");  
  229.                 exit(0);  
  230.             }  
  231.             break;  
  232.         }  
  233.     }  
  234.   
  235. }  

     上面的关于SDL的代码是为了移植到ARM开发板上用的,

    PC下编译的命令如下
                 gcc clientsdl.c -lpthread -o clientsdl -I/usr/local/include -L/usr/local/lib -lSDL -lSDL_image -lSDL_gfx

                 ./clientsdl 127.0..0.1

    ARM上的命令    arm-linux-gcc clientsdl.c -lpthread -o  armclientsdl  -I/usr/local/include -L/自己交叉编译库的路径  -lSDL -lSDL_image -lSDL_gfx

                 ./armclientsdl 127.0..0.1

运行结果截图:

嵌入式Linux网络编程

 

 

 嵌入式Linux网络编程