来源:自学PHP网 时间:2015-04-14 10:28 作者: 阅读:次
[导读] 嵌入式linux的网络编程(3)--TCP Client程序设计1 概述客户端主要需要完成与服务器建立连接,请求数据,应答数据等工作 从代码上来看,客户端程序有很多代码与服务器端程序类似,我们先给出...
嵌入式linux的网络编程(3)--TCP Client程序设计 1.概述客户端主要需要完成与服务器建立连接,请求数据,应答数据等工作.从代码上来看,客户端程序有很多代码与服务器端程序类似,我们先给出一个简单的客户端源码,随后进行详细的讲解. 1 /**************************************************************************************/ 2 /*简介:TCPClient示例。 */ 3 /*************************************************************************************/ 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <errno.h> 7 #include <string.h> 8 #include <netdb.h> 9 #include <sys/types.h> 10 #include <netinet/in.h> 11 #include <sys/socket.h> 12 13 int main(int argc, char *argv[]) 14 { 15 int sockfd; 16 char buffer[1024]; 17 struct sockaddr_in server_addr; 18 struct hostent *host; 19 int portnumber,nbytes; 20 21 if(argc!=3) 22 { 23 printf("Usage:%s hostname portnumber\a\n",argv[0]); 24 exit(1); 25 } 26 27 if((host=gethostbyname(argv[1]))==NULL) 28 { 29 herror ("Get host name error\n"); 30 exit(1); 31 } 32 33 if((portnumber=atoi(argv[2]))<0) 34 { 35 printf("Usage:%s hostname portnumber\a\n",argv[0]); 36 exit(1); 37 } 38 39 /* 客户程序开始建立 sockfd描述符 */ 40 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) 41 { 42 printf("Socket Error:%s\a\n",strerror(errno)); 43 exit(1); 44 } 45 /* 客户程序填充服务端的资料 */ 46 bzero(&server_addr,sizeof(server_addr)); 47 server_addr.sin_family=AF_INET; 48 server_addr.sin_port=htons(portnumber); 49 server_addr.sin_addr=*((struct in_addr *)host->h_addr); 50 /* 客户程序发起连接请求 */ 51 if(connect(sockfd,(struct sockaddr *)(&server_addr),\ 52 sizeof(struct sockaddr))==-1) 53 { 54 printf("Connect Error:%s(%d)\a\n",strerror(errno),errno); 55 exit(1); 56 } 57 /* 连接成功了 */ 58 if((nbytes=read(sockfd,buffer,1024))==-1) 59 { 60 printf("Read Error:%s\n",strerror(errno)); 61 exit(1); 62 } 63 buffer[nbytes]='\0'; 64 printf("I have received:%s\n",buffer); 65 66 /* 结束通讯 */ 67 close(sockfd); 68 exit(0); 69 }客户端程序首先连接到服务器端,然后才能进行数据交换,在这之前就必须知道服务器的IP地址和端口号. 2.名字地址转化通常,人们在使用过程中都不愿意记忆冗长的IP 地址,尤其到IPv6时,地址长度多达128位,那时就更加不可能一次次记忆那么长的IP地址了.因此,使用主机名将会是很好的选择.在Linux中,同样有一些函数可以实现主机名和地址的转化,最为常见的有gethostbyname,gethostbyaddr,getaddrinfo等,它们都可以实现IPv4和IPv6的地址和主机名之间的转化.其中gethostbyname是将主机名转化为IP地址,gethostbyaddr则是逆操作,是将IP地址转化为主机名,另外getaddrinfo还能实现自动识别IPv4地址和IPv6地址. struct hostent { char *h_name; /*正式主机名*/ char **h_aliases; /*主机别名*/ int h_addrtype; /*地址类型*/ int h_length; /*地址长度*/ char **h_addr_list; /*指向IPv4或IPv6的地址指针数组*/ }调用该函数后就能返回hostent结构体的相关信息.getaddrinfo函数涉及到一个addrinfo的结构体,如下所示: struct addrinfo { int ai_flags; /*AI_PASSIVE,AI_CANONNAME;*/ int ai_family; /*地址族*/ int ai_socktype; /*socket类型*/ int ai_protocol; /*协议类型*/ size_t ai_addrlen; /*地址长度*/ char *ai_canoname; /*主机名*/ struct sockaddr *ai_addr;/*socket结构体*/ struct addrinfo *ai_next;/*下一个指针链表*/ } 对hostent结构体而言,addrinfo结构体包含更多的信息. 如果该函数发生错误时,但全局变量errno中不存储错误代码,h_errno中存储的才是错误代码.通过herrno函数访问变量h_errno,该函数的使用与perror的用法一样,如果例子中的29行. 此外,还可以通过gethostname函数获得本地主机的名字,返回的名字可以用于gethostbyname,该函数的声明如下: #include <unistd.h> int gethostname(char *hostname, size_t size);hostname: 一个指向将要存放主机名的缓冲区指针; getaddrinfo函数的语法要点如下: 在调用之前,首先要对hints服务线索进行设置.它是一个addrinfo 结构体,下图列举了该结构体常见的选项值. 3.连接服务器当客户端完成创建socket,填充服务器信息结构等工作后,就可以连接服务器了,如例子中的第51行.connect函数的语法要点如下: 当connect函数出错时,全局变量errno含有下面的值: EACCES,EPERM 用户试图在套接字广播标志没有设置的情况下连接广播地址或由于防火墙策略导致连接失败. 当connect函数成功返回后,就可以使用sockfd作为与服务器连接的套接字描述符,一些之前提到的I/O函数,都可以用来与服务器进行通信了. 4.测试结果将这两个程序分别编译为simple_server和simple_client,通过SecureCRT建立两个和linux操作系统的连接,分别运行这两个程序. 注意:localhost是本地循环地址,它代表本机的IP地址,用点分十进制表示为127.0.0.1.这是一个特殊的IP地址,通常用来测试IP协议是否正常.在本地调试网络程序时会经常用到这个地址. |
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com