转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 数据库 >> MySql >> 正文
Linux网络编程,第一部分:BSD套接口篇(下)(翻译)         ★★★★

Linux网络编程,第一部分:BSD套接口篇(下)(翻译)

作者:闵涛 文章来源:闵涛的学习笔记 点击数:1837 更新时间:2009/4/22 20:45:44

(接上篇)
2、建立对应的客户端
    正如你正要看到的,相比服务端,客户端的代码就要简单多了。在这个程序中你必须提供两个命令行参数:服务端所在机器主机名或IP地址,和服务段绑定的端口。当然,服务端还必须在客户端运行以前就已经正常运行:P。

/*
 * Listing 2:
 * An example client for "Hello, World!" server
 * Ivan Griffin (ivan.griffin@ul.ie)
 */

/* Hellwolf Misty translated */

#include <stdio.h>                /* perror() */
#include <stdlib.h>               /* atoi() */
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>               /* read() */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

int main(int argc, char *argv[])
{
    int clientSocket,
        remotePort,
        status = 0;
    struct hostent *hostPtr = NULL;
    struct sockaddr_in serverName = { 0 };
    char buffer[256] = "";
    char *remoteHost = NULL;

    if (3 != argc)
    {
        fprintf(stderr, "Usage: %s
  \n",
            argv[0]);
        exit(1);
    }

    remoteHost = argv[1];
    remotePort = atoi(argv[2]);

    clientSocket = socket(PF_INET, SOCK_STREAM,
  IPPROTO_TCP);
    if (-1 == clientSocket)
    {
        perror("socket()");
        exit(1);
    }

    /*
     * 首先假定是DNS主机名
     * 注:
     * struct    hostent{
     *      char *h_name;       /* official name of host */
     *      char **h_aliases;   /* alias list */
     *      int  h_addrtype;    /* host address type */
     *      int  h_length;     /* length of address */
     *      char **h_addr_list; /* list of addresses from name server */
     * };
     * #define   h_addr  h_addr_list[0] 
     * 注意到了吗?h_addr是一个宏,如果你用gdb调试时
     * display phostent->h_addr出错的话不要奇怪
     */
    hostPtr = gethostbyname(remoteHost); /* struct hostent *hostPtr; */
    if (NULL == hostPtr)
    {/* 不是?? */
        hostPtr = gethostbyaddr(remoteHost,
  strlen(remoteHost), AF_INET);/* 应该是点分形式的IP地址吧*/
        if (NULL == hostPtr) /* 还不是,!-_- */
        {
        perror("Error resolving server address");
        exit(1);
        }
    }

    serverName.sin_family = AF_INET;
    serverName.sin_port = htons(remotePort);
    (void) memcpy(&serverName.sin_addr,
     hostPtr->h_addr,
     hostPtr->h_length);

/* 这里并不需要再bind了,因为connect已经可以为我们解决一切 */
    status = connect(clientSocket,
        (struct sockaddr*) &serverName,
                      sizeof(serverName));
    if (-1 == status)
    {
        perror("connect()");
        exit(1);
    }
/* connect成功后,一个双工(duplex)的网络连接就被建立好了
 * 像服务器一样,客户端可以使用read()和write()接收数据
    /*
     * 客户端的具体代码应该从这里开始实施
     * 比如从服务端接受和回应信息等等
     */
    while (0 < (status = read(clientSocket,
                               buffer, sizeof(buffer) - 1)))
    {
        printf("%d: %s", status, buffer);
        /* 注:如果读成功,status表示获得的字节数(包括''''\0'''') */
    }

    if (-1 == status)
    {
        perror("read()");
    }

    close(clientSocket);

    return 0;
}

需要注意的几点:

  • 发送文字通常都工作正常。但是记住不同的系统对换行的实现有差别(比如,Unix使用\0x12,而微软使用\0x15\0x12)。
  • 不同的实现可能使用不同的字节序(byte-order)。但不用担心,BSD的设计者们在一考虑了这一点。有很多现成的函数实现了这种转换,他们都有一定的命名规则:htons代表实现host-to-network的short结构的转换,还有htonl,ntohs,ntohl,也很容易判断出他们的工作方式。至于网络字节序是大端对齐(big-endian)还是小端对齐(little-endian)并不是个问题,因为在TCP/IP网络上它已经被标准化了(注:网络字节序用的是大端对齐)。当然除非你一直在网络上发一个字符(注:还得是ASCII的),不用这些转换函数不会引起大问题,但通常情况下,你会遭遇到字节序问题。这还要看你的机器,有时侯这些函数就是一个空宏,有时候它们确实是函数。有趣的是,最常见的网络编程的bugs来源是忘记了在填充sockaddr_in结构的sin_addr.s_addr字段时忘记了使用这些函数,即使使用INADDR_ANY也必须这么做。
  • 网络编程的一个重要目标就是不给双方带来不可预料的麻烦。比如说,服务器在访问关键数据时必须通过必要的机制同步对这部分资源的访问,避免由此带来的死锁并且保证数据的有效性。
  • 大多数情况下,你不能从机器间传递指针并试图使用它。
    <>类似的,大多数情况下,你也不能试图通过套接口传递一个文件描述符从一个进程到另一个进程(非子进程)并直接使用它。BSD和SVR4系统提供了在不相关的进程间传递文件描述符的不同方法;然而,在linux下最简单的方法就是通过使用/proc文件系统。
       
  • 此外,你必须保证你正确的解决了short writes问题。Short write发生在write()调用仅仅部分的将缓冲区写给一个文件描述符对应的设备。它们发生的原因归咎于操作系统的缓冲区,和底层传输系统的流控制系统。某些系统调用,通常被称作慢系统调用(slow system calls)可能会被(其他调用)中断。一些可能不会被自动重起,所以你必须明确地在网络编程时解决这一问题。下面的代码解决了short write问题:
    /*
     * Listing 3:
     * Handling short writes
     * Ivan Griffin (ivan.griffin@ul.ie)
     */
    /* Hellwolf Misty translated */
    int bytesToSend = 0,
        bytesWritten = 0,
        num = 0;

/*
 * 这里用到的bytesToSend, buffer, and
 * fileDesc必须已经在其他某个地方有定义.
 */

for (bytesWritten = 0; bytesWritten < bytesToSend;
     bytesWritten += num)
{
    num = write(fileDesc,
        (void *)( (char *)buffer +
  (char *)bytesWritten ),
        bytesToSend - bytesWritten);

    if (num < 0)
    {
        perror("write()");

        if (errno != EINTR)
        {
            exit(1);
        }
    }
}

使用多线程而不是多进程可能会减轻服务器的负担,并且更加有效。线程间上下文的转化(当然是指同一个进程空间)通常开销比进程间上下文转换小得多。然而,如此多的子线程都在操作网络I/O,如果它们在内核级还可以,但如果它们是用户级的,整个进程都会因为第一个调用I/O的线程而阻塞。这将会导致不愿看到的其他线程的饥饿状态直到I/O的完成。正如你看到的,当使用简单的forking模型时在父进程和子进程中关闭不必要的套接口文件描述符是相当寻常的。这保护了进程潜在的错误读写这些描述符的可能性。但是不要试图在使用线程模型时这样做,进程中的多线程共享同一个内存虚拟地址空间和文件描述符集。如果你在一个线程中关闭了一个描述符,那么进程中的其他所有的线程都将无法得到该描述符。

3、无连接的数据传输——UDP
   下面的代码显示了一个使用UDP的服务端。UDP程序很像TCP程序,但他们又很大的不同。首先,UDP不保证可靠的传输——如果你需要在使用UDP时获得可靠性,你必须或者自己实现或者转而用TCP。
  
   像TCP程序一样,用UDP你可以建立一个套接口并将其绑定到特定地址。UDP服务端不监听(listen)和接受(accept)外来的连接,客户也不必显式的连接到服务器。事实上,在UDP客户端和服务段之间并没有太大的区别。服务端必须绑定到一个确定的端口和地址好让客户端知道向哪里发送数据。而且当你的服务端使用send(),客户端也应该使用对应的recv族函数。
UDP服务端程序清单:
/*
 * Listing 4:
 * Example UDP (connectionless) server
 * Ivan Griffin (ivan.griffin@ul.ie)
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define MAX_MESG_SIZE 4096
char mesg[MAX_MESG_SIZE] = "";

int main(int argc, char *argv[])
{
    int udpSocket = 0,
        myPort = 0,
        status = 0,
        size = 0,
        clientLength = 0;
  &

[1] [2]  下一页


[C语言系列]C#网络编程客户端程序实现源码分享  [Web开发]JavaScript 面向对象编程, 第一部分: 继承
[MySql]值得关注的MySQL 4.1.1进展 (第一部分)  [MySql]Linux网络编程,第一部分:BSD套接口篇(上)
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · Sql Server  · MySql
    · Access  · ORACLE
    · SyBase  · 其他
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台