嵌入式linux的网络编程 2 --TCP Server程序设计

               

嵌入式linux的网络编程(2)--TCP Server程序设计

CSDN2013年度博客之星评选活动开始,本人有幸入围参加评选,如果博客中的文章对你有所帮助,请为 ce123 投上宝贵一票,非常感谢!
投票地址:http://vote.blog.csdn.net/blogstaritem/blogstar2013/ce123

 前面简单介绍了TCP/IP协议,事实上该协议非常复杂,要编写一个优秀的网络程序也非易事.下面我们通过一个例子的学习达到对网络编程有一个概貌性的理解.

1.TCP的通信过程

 一个典型的TCP通信过程如下:


 工作过程如下:服务器首先启动,通过调用socket建立一个套接字,然后调用bind将该套接字和本地网络地址联系在一起,再调用listen使套接字做好侦听的准备,并规定它的请求队列的长度,之后调用accept来接收连接.客户在建立套接字后就可以调用connect和服务器建立连接连接一旦建立,客户机和服务器之间就可以通过调用read和write来发送和接收数据.最后,待数据传送结束后,双方调用close关闭套接字.

2.TCP Server程序

 为了学习基于socket编程的基本流程和所用到的API函数,下面我们通过一个实际的例子来学习.该例子包含服务器程序和客户端程序.首先列出服务器程序的源码,后续的文章中再讲解客户端程序.

  1 /**************************************************************************************/  2 /*简介:TCPServer示例。                                                                  */  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,new_fd;         16         struct sockaddr_in server_addr;   17         struct sockaddr_in client_addr;   18         int sin_size,portnumber;   19         const char hello[]="Hello\n"; 20  21         if(argc!=2)  22         {  23                 printf("Usage:%s portnumber\a\n",argv[0]);  24                 exit(1);  25         }  26         if((portnumber=atoi(argv[1]))<0)  27         {  28                 printf("Usage:%s portnumber\a\n",argv[0]);  29                 exit(1);  30         }  31  32         /* 服务器端开始建立socket描述符 */  33         if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)  34         {  35                 printf("Socket error:%s\n\a",strerror(errno));  36                 exit(1);  37         }  38  39         /* 服务器端填充 sockaddr结构 */  40         bzero(&server_addr,sizeof(struct sockaddr_in));  41         server_addr.sin_family=AF_INET;  42         server_addr.sin_addr.s_addr=htonl(INADDR_ANY);  43         server_addr.sin_port=htons(portnumber);  44  45         /* 捆绑sockfd描述符 */  46         if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))== -1) 47         { 48                 printf("Bind error:%s\n\a",strerror(errno)); 49                 exit(1); 50         } 51  52         /* 监听sockfd描述符 */ 53         if(listen(sockfd,5)==-1) 54         { 55                 printf("Listen error:%s\n\a",strerror(errno)); 56                 exit(1); 57         } 58  59         while(1) 60         { 61                 /* 服务器阻塞,直到客户程序建立连接 */ 62                 sin_size=sizeof(struct sockaddr_in); 63                 if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1) 64                 { 65                         printf("Accept error:%s(%d)\n\a",strerror(errno),errno); 66                         exit(1); 67                 } 68                 printf("Server get connection from %s\n", 69                                 (char *)inet_ntoa(client_addr.sin_addr)); 70  71                 if(write(new_fd,hello,strlen(hello))==-1) 72                 { 73                         printf("Write Error:%s\n",strerror(errno)); 74                         exit(1); 75                 } 76                 /* 这个通讯已经结束 */ 77                 close(new_fd); 78                 /* 循环下一个 */ 79         } 80  81         close(sockfd); 82         exit(0); 83 }

  接下来我们对该例子进行详细的讲解.

2.1.网络地址的表示

 在引入的众多的头文件后,源码的16和17行定义了两个sockaddr_in数据类型的变量.它们分别表示服务器和客户端的网络地址.网络地址的表示主要通过socketaddr和sockaddr_in来表示.下面首先介绍两个重要的数据类型:sockaddr和sockaddr_in,这两个结构类型都是用来保存socket信息的,如下所示:

struct sockaddr { unsigned short sa_family; /*地址族*/ char sa_data[14];  /*14字节的协议地址,包含该socket的IP地址和端口号。*/};struct sockaddr_in { short int sa_family;   /*地址族*/ unsigned short int sin_port; /*端口号*/ struct in_addr sin_addr; /*IP地址*/ unsigned char sin_zero[8]; /*填充0 以保持与struct sockaddr同样大小*/};// Internet address.struct in_addr {        union {                struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;                struct { u_short s_w1,s_w2; } S_un_w;                u_long S_addr; /* port in network byte order */        } S_un;#define s_addr  S_un.S_addr};// Socket address, internet style.struct sockaddr_in {        // struct sockaddr的一种特殊形式        short            sin_family;    /* address family: AF_INET */        u_short        sin_port;        /* port in network byte order */        struct in_addr sin_addr;        /* port in network byte order */        char            sin_zero[8];    /* 8 byte pad */};// Structure used by kernel to store most addresses.struct sockaddr {        u_short sa_family; /* address family */        char    sa_data[14]; /* up to 14 bytes of direct address */};

 这两个数据类型是等效的,可以相互转化,通常sockaddr_in数据类型使用更为方便.但需要注意的是sin_zero[8]是为了使两个结构体在内存中具有相同的尺寸,使用sockaddr_in的时候要把sin_zero全部设为0.在建立socketadd或sockaddr_in后,就可以对该socket进行适当的操作了.下图列出了该结构sa_family字段可选的常见值.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值