DIY编程器网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 1061|回复: 0
打印 上一主题 下一主题

[待整理] 嵌入式Linux网络编程之:网络基础编程

[复制链接]
跳转到指定楼层
楼主
发表于 2014-10-10 07:33:17 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
        10.2  网络基础编程

        10.2.1  socket概述

        1.socket定义

        在Linux中的网络编程是通过socket接口来进行的。人们常说的socket是一种特殊的I/O接口,它也是一种文件描述符。socket是一种常用的进程之间通信机制,通过它不仅能实现本地机器上的进程之间的通信,而且通过网络能够在不同机器上的进程之间进行通信。
         
        每一个socket都用一个半相关描述{协议、本地地址、本地端口}来表示;一个完整的套接字则用一个相关描述{协议、本地地址、本地端口、远程地址、远程端口}来表示。socket也有一个类似于打开文件的函数调用,该函数返回一个整型的socket描述符,随后的连接建立、数据传输等操作都是通过socket来实现的。
         
        2.socket类型

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

        1.地址结构相关处理

        (1)数据结构介绍。
        下面首先介绍两个重要的数据类型: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同样大小*/
        };
         
        这两个数据类型是等效的,可以相互转化,通常sockaddr_in数据类型使用更为方便。在建立socketadd或sockaddr_in后,就可以对该socket进行适当的操作了。
         
        (2)结构字段。
        表10.1列出了该结构sa_family字段可选的常见值。
        表10.1
                                                                        结构定义头文件
                       
                                                                        #include <netinet/in.h>
                       
                                                                        sa_family
                       
                                                                        AF_INET:IPv4协议
                       
                                                                        AF_INET6:IPv6协议
                       
                                                                        AF_LOCAL:UNIX域协议
                       
                                                                        AF_LINK:链路地址协议
                       
                                                                        AF_KEY:密钥套接字(socket)
                       
         
        sockaddr_in其他字段的含义非常清楚,具体的设置涉及其他函数,在后面会有详细的讲解。
         
        2.数据存储优先顺序

        (1)函数说明。
        计算机数据存储有两种字节优先顺序:高位字节优先(称为大端模式)和低位字节优先(称为小端模式,PC机通常采用小端模式)。Internet上数据以高位字节优先顺序在网络上传输,因此在有些情况下,需要对这两个字节存储优先顺序进行相互转化。这里用到了4个函数:htons()、ntohs()、htonl()和ntohl()。这4个地址分别实现网络字节序和主机字节序的转化,这里的h代表host,n代表network,s代表short,l代表long。通常16位的IP端口号用s代表,而IP地址用l来代表。
         
        (2)函数格式说明。
        表10.2列出了这4个函数的语法格式。
        表10.2 htons等函数语法要点
                                                                        所需头文件
                       
                                                                        #include <netinet/in.h>
                       
                                                                        函数原型
                       
                                                                        uint16_t htons(unit16_t host16bit)
                                        uint32_t htonl(unit32_t host32bit)
                                        uint16_t ntohs(unit16_t net16bit)
                                        uint32_t ntohs(unit32_t net32bit)
                       
                                                                        函数传入值
                       
                                                                        host16bit:主机字节序的16位数据
                       
                                                                         
                       
                                                                        host32bit:主机字节序的32位数据
                       
                                                                        net16bit:网络字节序的16位数据
                       
                                                                        net32bit:网络字节序的32位数据
                       
                                                                        函数返回值
                       
                                                                        成功:返回要转换的字节序
                       
                                                                        出错:-1
                       
         
                                                                        注意
                       
                                                                        调用该函数只是使其得到相应的字节序,用户不需清楚该系统的主机字节序和网络字节序是否真正相等。如果是相同不需要转换的话,该系统的这些函数会定义成空宏。
                       
         
        3.地址格式转化

        (1)函数说明。
        通常用户在表达地址时采用的是点分十进制表示的数值(或者是以冒号分开的十进制IPv6地址),而在通常使用的socket编程中所使用的则是二进制值,这就需要将这两个数值进行转换。这里在IPv4中用到的函数有inet_aton()、inet_addr()和inet_ntoa(),而IPv4和IPv6兼容的函数有inet_pton()和inet_ntop()。由于IPv6是下一代互联网的标准协议,因此,本书讲解的函数都能够同时兼容IPv4和IPv6,但在具体举例时仍以IPv4为例。
         
        这里inet_pton()函数是将点分十进制地址映射为二进制地址,而inet_ntop()是将二进制地址映射为点分十进制地址。
         
        (2)函数格式。
        表10.3列出了inet_pton函数的语法要点。
        表10.3 inet_pton函数语法要点
                                                                        所需头文件
                       
                                                                        #include <arpa/inet.h>
                       
                                                                        函数原型
                       
                                                                        int inet_pton(int family, const char *strptr, void *addrptr)
                       
                                                                        函数传入值
                       
                                                                        family
                       
                                                                        AF_INET:IPv4协议
                       
                                                                        AF_INET6:IPv6协议
                       
                                                                        strptr:要转化的值
                       
                                                                        addrptr:转化后的地址
                       
                                                                        函数返回值
                       
                                                                        成功:0
                       
                                                                        出错:-1
                       
         
        表10.4列出了inet_ntop函数的语法要点。
        表10.4 inet_ntop函数语法要点
                                                                        所需头文件
                       
                                                                        #include <arpa/inet.h>
                       
                                                                        函数原型
                       
                                                                        int inet_ntop(int family, void *addrptr, char *strptr, size_t len)
                       
                                                                        函数传入值
                       
                                                                        family
                       
                                                                        AF_INET:IPv4协议
                       
                                                                        AF_INET6:IPv6协议
                       
                                                                        函数传入值
                       
                                                                        addrptr:转化后的地址
                       
                                                                        strptr:要转化的值
                       
                                                                        len:转化后值的大小
                       
                                                                        函数返回值
                       
                                                                        成功:0
                       
                                                                        出错:-1
                       
         

        4.名字地址转化

        (1)函数说明。
        通常,人们在使用过程中都不愿意记忆冗长的IP地址,尤其到IPv6时,地址长度多达128位,那时就更加不可能一次次记忆那么长的IP地址了。因此,使用主机名将会是很好的选择。在Linux中,同样有一些函数可以实现主机名和地址的转化,最为常见的有gethostbyname()、gethostbyaddr()和getaddrinfo()等,它们都可以实现IPv4和IPv6的地址和主机名之间的转化。其中gethostbyname()是将主机名转化为IP地址,gethostbyaddr()则是逆操作,是将IP地址转化为主机名,另外getaddrinfo()还能实现自动识别IPv4地址和IPv6地址。
        gethostbyname()和gethostbyaddr()都涉及一个hostent的结构体,如下所示:
         
        struct hostent
        {
               char *h_name;/*正式主机名*/
               char **h_aliases;/*主机别名*/
               int h_addrtype;/*地址类型*/
               int h_length;/*地址字节长度*/
               char **h_addr_list;/*指向IPv4或IPv6的地址指针数组*/
        }
         
        调用gethostbyname()函数或gethostbyaddr()函数后就能返回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_canonname;/*主机名*/
               struct sockaddr *ai_addr;/*socket结构体*/
               struct addrinfo *ai_next;/*下一个指针链表*/
        }
         
        hostent结构体而言,addrinfo结构体包含更多的信息。
         
        (2)函数格式。
        表10.5列出了gethostbyname()函数的语法要点。
        表10.5 gethostbyname函数语法要点
                                                                        所需头文件
                       
                                                                        #include <netdb.h>
                       
                                                                        函数原型
                       
                                                                        struct hostent *gethostbyname(const char *hostname)
                       
                                                                        函数传入值
                       
                                                                        hostname:主机名
                       
                                                                        函数返回值
                       
                                                                        成功:hostent类型指针
                       
                                                                        出错:-1
                       
         
        调用该函数时可以首先对hostent结构体中的h_addrtype和h_length进行设置,若为IPv4可设置为AF_INET和4;若为IPv6可设置为AF_INET6和16;若不设置则默认为IPv4地址类型。
         
        表10.6列出了getaddrinfo()函数的语法要点。
        表10.6 getaddrinfo()函数语法要点
                                                                        所需头文件
                       
                                                                        #include <netdb.h>
                       
                                                                        函数原型
                       
                                                                        int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **result)
                       
                                                                        函数传入值
                       
                                                                        node:网络地址或者网络主机名
                       
                                                                        service:服务名或十进制的端口号字符串
                       
                                                                        hints:服务线索
                       
                                                                        result:返回结果
                       
                                                                        函数返回值
                       
                                                                        成功:0
                       
                                                                        出错:-1
                       
         
        在调用之前,首先要对hints服务线索进行设置。它是一个addrinfo结构体,表10.7列举了该结构体常见的选项值。
        表10.7 addrinfo结构体常见选项值
                                                                        结构体头文件
                       
                                                                        #include <netdb.h>
                       
                                                                        ai_flags
                       
                                                                        AI_PASSIVE:该套接口是用作被动地打开
                       
                                                                        AI_CANONNAME:通知getaddrinfo函数返回主机的名字
                       
                                                                        ai_family
                       
                                                                        AF_INET:IPv4协议
                       
                                                                        AF_INET6:IPv6协议
                       
                                                                        AF_UNSPEC:IPv4或IPv6均可
                       
                                                                        ai_socktype
                       
                                                                        SOCK_STREAM:字节流套接字socket(TCP)
                       
                                                                         
                       
                                                                        SOCK_DGRAM:数据报套接字socket(UDP)
                       
                                                                        ai_protocol
                       
                                                                        IPPROTO_IP:IP协议
                       
                                                                        IPPROTO_IPV4:IPv4协议
                       
                                                                        4
                       
                                                                        IPv4
                       
                                                                        IPPROTO_IPV6:IPv6协议
                       
                                                                        IPPROTO_UDP:UDP
                       
                                                                        IPPROTO_TCP:TCP
                       
         
                                                                        注意
                       
                                                                        (1)通常服务器端在调用getaddrinfo()之前,ai_flags设置AI_PASSIVE,用于bind()函数(用于端口和地址的绑定,后面会讲到),主机名nodename通常会设置为NULL。
                                                                        (2)客户端调用getaddrinfo()时,ai_flags一般不设置AI_PASSIVE,但是主机名nodename和服务名servname(端口)则应该不为空。
                                                                        (3) 即使不设置ai_flags为AI_PASSIVE,取出的地址也可以被绑定,很多程序中ai_flags直接设置为0,即3个标志位都不设置,这种情况下只要hostname和servname设置的没有问题就可以正确绑定。
                       
         
        (3)使用实例。
        下面的实例给出了getaddrinfo函数用法的示例,在后面小节中会给出gethostbyname函数用法的例子。
         
        /* getaddrinfo.c */
        #include <stdio.h>
        #include <stdlib.h>
        #include <errno.h>
        #include <string.h>
        #include <netdb.h>
        #include <sys/types.h>
        #include <netinet/in.h>
        #include <sys/socket.h>
         
        int main()
        {
             struct addrinfo hints, *res = NULL;
             int rc;
             
             memset(&hints, 0, sizeof(hints));
             /*设置addrinfo结构体中各参数 */
             hints.ai_flags = AI_CANONNAME;
             hints.ai_family = AF_UNSPEC;
             hints.ai_socktype = SOCK_DGRAM;
             hints.ai_protocol = IPPROTO_UDP;
             /*调用getaddinfo函数*/
             rc = getaddrinfo("localhost", NULL, &hints, &res);
             if (rc != 0)
             {
                  perror("getaddrinfo");
                  exit(1);
             }
             else
             {
                  printf("Host name is %s\n", res->ai_canonname);
             }
             exit(0);
        }
         
        10.2.3  socket基础编程

        (1)函数说明。
        socket编程的基本函数有socket()、bind()、listen()、accept()、send()、sendto()、recv()以及recvfrom()等,其中根据客户端还是服务端,或者根据使用TCP协议还是UDP协议,这些函数的调用流程都有所区别,这里先对每个函数进行说明,再给出各种情况下使用的流程图。
         
        n socket():该函数用于建立一个socket连接,可指定socket类型等信息。在建立了socket连接之后,可对sockaddr或sockaddr_in结构进行初始化,以保存所建立的socket地址信息。
         
        n bind():该函数是用于将本地IP地址绑定到端口号,若绑定其他IP地址则不能成功。另外,它主要用于TCP的连接,而在UDP的连接中则无必要。
        n listen():在服务端程序成功建立套接字和与地址进行绑定之后,还需要准备在该套接字上接收新的连接请求。此时调用listen()函数来创建一个等待队列,在其中存放未处理的客户端连接请求。
        n accept():服务端程序调用listen()函数创建等待队列之后,调用accept()函数等待并接收客户端的连接请求。它通常从由bind()所创建的等待队列中取出第一个未处理的连接请求。
        n connect():该函数在TCP中是用于bind()的之后的client端,用于与服务器端建立连接,而在UDP中由于没有了bind()函数,因此用connect()有点类似bind()函数的作用。
        n send()和recv():这两个函数分别用于发送和接收数据,可以用在TCP中,也可以用在UDP中。当用在UDP时,可以在connect()函数建立连接之后再用。
        n sendto()和recvfrom():这两个函数的作用与send()和recv()函数类似,也可以用在TCP和UDP中。当用在TCP时,后面的几个与地址有关参数不起作用,函数作用等同于send()和recv();当用在UDP时,可以用在之前没有使用connect()的情况下,这两个函数可以自动寻找指定地址并进行连接。
         
        服务器端和客户端使用TCP协议的流程如图10.6所示。
        服务器端和客户端使用UDP协议的流程如图10.7所示。
                    

        图10.6  使用TCP协议socket编程流程图             图10.7  使用UDP协议socket编程流程图

         
        (2)函数格式。
        表10.8列出了socket()函数的语法要点。
        表10.8 socket()函数语法要点
                                                                        所需头文件
                       
                                                                        #include <sys/socket.h>
                       
                                                                        函数原型
                       
                                                                        int socket(int family, int type, int protocol)
                       
                                                                        函数传入值
                       
                                                                        family:
                                                                        协议族
                       
                                                                        AF_INET:IPv4协议
                       
                                                                        AF_INET6:IPv6协议
                       
                                                                        AF_LOCAL:UNIX域协议
                       
                                                                        AF_ROUTE:路由套接字(socket)
                       
                                                                        AF_KEY:密钥套接字(socket)
                       
                                                                        type:
                                                                        套接字类型
                       
                                                                        SOCK_STREAM:字节流套接字socket
                       
                                                                        SOCK_DGRAM:数据报套接字socket
                       
                                                                        SOCK_RAW:原始套接字socket
                       
                                                                        protoco:0(原始套接字除外)
                       
                                                                        函数返回值
                       
                                                                        成功:非负套接字描述符
                       
                                                                        出错:-1
                       
         
        表10.9列出了bind()函数的语法要点。
        表10.9 bind()函数语法要点
                                                                        所需头文件
                       
                                                                        #include <sys/socket.h>
                       
                                                                        函数原型
                       
                                                                        int bind(int sockfd, struct sockaddr *my_addr, int addrlen)
                       
                                                                        函数传入值
                       
                                                                        socktd:套接字描述符
                       
                                                                        my_addr:本地地址
                       
                                                                        addrlen:地址长度
                       
                                                                        函数返回值
                       
                                                                        成功:0
                       
                                                                        出错:-1
                       
         
        端口号和地址在my_addr中给出了,若不指定地址,则内核随意分配一个临时端口给该应用程序。
         
        表10.10列出了listen()函数的语法要点。
        表10.10 listen()函数语法要点
                                                                        所需头文件
                       
                                                                        #include <sys/socket.h>
                       
                                                                        函数原型
                       
                                                                        int listen(int sockfd, int backlog)
                       
                                                                        函数传入值
                       
                                                                        socktd:套接字描述符
                       
                                                                        backlog:请求队列中允许的最大请求数,大多数系统缺省值为5
                       
                                                                        函数返回值
                       
                                                                        成功:0
                       
                                                                        出错:-1
                       
         
        表10.11列出了accept()函数的语法要点。
        表10.11 accept()函数语法要点
                                                                        所需头文件
                       
                                                                        #include <sys/socket.h>
                       
                                                                        函数原型
                       
                                                                        int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
                       
                                                                        函数传入值
                       
                                                                        socktd:套接字描述符
                       
                                                                        addr:客户端地址
                       
                                                                        addrlen:地址长度
                       
                                                                        函数返回值
                       
                                                                        成功:0
                       
                                                                        出错:-1
                       
         
        表10.12列出了connect()函数的语法要点。
        表10.12 connect()函数语法要点
                                                                        所需头文件
                       
                                                                        #include <sys/socket.h>
                       
                                                                        函数原型
                       
                                                                        int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)
                       
                                                                        函数传入值
                       
                                                                        socktd:套接字描述符
                       
                                                                        serv_addr:服务器端地址
                       
                                                                        addrlen:地址长度
                       
                                                                        函数返回值
                       
                                                                        成功:0
                       
                                                                        出错:-1
                       
         
        表10.13列出了send()函数的语法要点。
        表10.13 send()函数语法要点
                                                                        所需头文件
                       
                                                                        #include <sys/socket.h>
                       
                                                                        函数原型
                       
                                                                        int send(int sockfd, const void *msg, int len, int flags)
                       
                                                                        函数传入值
                       
                                                                        socktd:套接字描述符
                       
                                                                        msg:指向要发送数据的指针
                       
                                                                        len:数据长度
                       
                                                                        flags:一般为0
                       
                                                                        函数返回值
                       
                                                                        成功:发送的字节数
                       
                                                                        出错:-1
                       
         
        表10.14列出了recv()函数的语法要点。
        表10.14 recv()函数语法要点
                                                                        所需头文件
                       
                                                                        #include <sys/socket.h>
                       
                                                                        函数原型
                       
                                                                        int recv(int sockfd, void *buf,int len, unsigned int flags)
                       
                                                                        函数传入值
                       
                                                                        socktd:套接字描述符
                       
                                                                        buf:存放接收数据的缓冲区
                       
                                                                        len:数据长度
                       
                                                                        flags:一般为0
                       
                                                                        函数返回值
                       
                                                                        成功:接收的字节数
                       
                                                                        出错:-1
                       
         
        表10.15列出了sendto()函数的语法要点。
        表10.15 sendto()函数语法要点
                                                                        所需头文件
                       
                                                                        #include <sys/socket.h>
                       
                                                                        函数原型
                       
                                                                        int sendto(int sockfd, const void *msg,int len, unsigned int flags, const struct sockaddr *to, int tolen)
                       
                                                                        函数传入值
                       
                                                                        socktd:套接字描述符
                       
                                                                        msg:指向要发送数据的指针
                       
                                                                        len:数据长度
                       
                                                                        flags:一般为0
                       
                                                                        to:目地机的IP地址和端口号信息
                       
                                                                        tolen:地址长度
                       
                                                                        函数返回值
                       
                                                                        成功:发送的字节数
                       
                                                                        出错:-1
                       
         
        表10.16列出了recvfrom()函数的语法要点。
        表10.16 recvfrom()函数语法要点
                                                                        所需头文件
                       
                                                                        #include <sys/socket.h>
                       
                                                                        函数原型
                       
                                                                        int recvfrom(int sockfd,void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen)
                       
                                                                        函数传入值
                       
                                                                        socktd:套接字描述符
                       
                                                                        buf:存放接收数据的缓冲区
                       
                                                                        len:数据长度
                       
                                                                        flags:一般为0
                       
                                                                        from:源主机的IP地址和端口号信息
                       
                                                                        tolen:地址长度
                       
                                                                        函数返回值
                       
                                                                        成功:接收的字节数
                       
                                                                        出错:-1
                       
         
        (3)使用实例。
        该实例分为客户端和服务器端两部分,其中服务器端首先建立起socket,然后与本地端口进行绑定,接着就开始接收从客户端的连接请求并建立与它的连接,接下来,接收客户端发送的消息。客户端则在建立socket之后调用connect()函数来建立连接。
        服务端的代码如下所示:
         
        /*server.c*/
        #include <sys/types.h>
        #include <sys/socket.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <errno.h>
        #include <string.h>
        #include <unistd.h>
        #include <netinet/in.h>
         
        #define PORT            4321
        #define BUFFER_SIZE        1024
        #define MAX_QUE_CONN_NM   5
         
        int main()
        {
             struct sockaddr_in server_sockaddr,client_sockaddr;
             int sin_size,recvbytes;
             int sockfd, client_fd;
             char buf[BUFFER_SIZE];
             
             /*建立socket连接*/
             if ((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1)
             {
                  perror("socket");
                  exit(1);
             }
             printf("Socket id = %d\n",sockfd);
             
             /*设置sockaddr_in 结构体中相关参数*/
             server_sockaddr.sin_family = AF_INET;
             server_sockaddr.sin_port = htons(PORT);
             server_sockaddr.sin_addr.s_addr = INADDR_ANY;
             bzero(&(server_sockaddr.sin_zero), 8);
             
             int i = 1;/* 允许重复使用本地地址与套接字进行绑定 */
             setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
             
             /*绑定函数bind()*/
             if (bind(sockfd, (struct sockaddr *)&server_sockaddr,
                           sizeof(struct sockaddr)) == -1)
             {
                  perror("bind");
                  exit(1);
             }
             printf("Bind success!\n");
             
             /*调用listen()函数,创建未处理请求的队列*/
             if (listen(sockfd, MAX_QUE_CONN_NM) == -1)
             {
                  perror("listen");
                  exit(1);
             }
             printf("Listening....\n");
             
             /*调用accept()函数,等待客户端的连接*/
             if ((client_fd = accept(sockfd,
                          (struct sockaddr *)&client_sockaddr, &sin_size)) == -1)
             {
                  perror("accept");
                  exit(1);
             }
             
             /*调用recv()函数接收客户端的请求*/
             memset(buf , 0, sizeof(buf));
             if ((recvbytes = recv(client_fd, buf, BUFFER_SIZE, 0)) == -1)
             {
                  perror("recv");
                  exit(1);
             }
             printf("Received a message: %s\n", buf);
             close(sockfd);
             exit(0);
        }
         
        客户端的代码如下所示:
         
        /*client.c*/
        #include <stdio.h>
        #include <stdlib.h>
        #include <errno.h>
        #include <string.h>
        #include <netdb.h>
        #include <sys/types.h>
        #include <netinet/in.h>
        #include <sys/socket.h>
         
        #define PORT   4321
        #define BUFFER_SIZE 1024
         
        int main(int argc, char *argv[])
        {
             int sockfd,sendbytes;
             char buf[BUFFER_SIZE];
             struct hostent *host;
             struct sockaddr_in serv_addr;
             
             if(argc < 3)
             {
                  fprintf(stderr,"USAGE: ./client Hostname(or ip address) Text\n");
                  exit(1);
             }
             
             /*地址解析函数*/
             if ((host = gethostbyname(argv[1])) == NULL)
             {
                  perror("gethostbyname");
                  exit(1);
             }
             
             memset(buf, 0, sizeof(buf));
             sprintf(buf, "%s", argv[2]);
             
             /*创建socket*/
             if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
             {
                  perror("socket");
                  exit(1);
             }
             
             /*设置sockaddr_in 结构体中相关参数*/
             serv_addr.sin_family = AF_INET;
             serv_addr.sin_port = htons(PORT);
             serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
             bzero(&(serv_addr.sin_zero), 8);
             
             /*调用connect函数主动发起对服务器端的连接*/
             if(connect(sockfd,(struct sockaddr *)&serv_addr,
                                           sizeof(struct sockaddr))== -1)
             {
                  perror("connect");
                  exit(1);
             }
             
             /*发送消息给服务器端*/
             if ((sendbytes = send(sockfd, buf, strlen(buf), 0)) == -1)
             {
                  perror("send");
                  exit(1);
             }
             close(sockfd);
             exit(0);
        }
         
        在运行时需要先启动服务器端,再启动客户端。这里可以把服务器端下载到开发板上,客户端在宿主机上运行,然后配置双方的IP地址,在确保双方可以通信(如使用ping命令验证)的情况下运行该程序即可。
         
        $ ./server
        Socket id = 3
        Bind success!
        Listening....
        Received a message: Hello,Server!
        $ ./client localhost(或者输入IP地址) Hello,Server!
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|文字版|手机版|DIY编程器网 ( 桂ICP备14005565号-1 )

GMT+8, 2024-11-14 15:06 , 耗时 0.096411 秒, 22 个查询请求 , Gzip 开启.

各位嘉宾言论仅代表个人观点,非属DIY编程器网立场。

桂公网安备 45031202000115号

DIY编程器群(超员):41210778 DIY编程器

DIY编程器群1(满员):3044634 DIY编程器1

diy编程器群2:551025008 diy编程器群2

QQ:28000622;Email:libyoufer@sina.com

本站由桂林市临桂区技兴电子商务经营部独家赞助。旨在技术交流,请自觉遵守国家法律法规,一旦发现将做封号删号处理。

快速回复 返回顶部 返回列表