互联网

SOCK_STREAM

SOCK_STREAM

  • 外文名:SOCK_STREAM
  • 别名:TCP协议
  • 所属领域:C语言
  • 发起人:C语言socket编程
  • 发起单位:C语言socket编程
  • SOCK_STREAM介绍
    SOCK_STREAM提供面向连接的稳定数据传输,即TCP协议。SOCK_STREAM应用在C语言socket编程中,在进行网络连接前,需要用socket函数向系统申请一个通信端口。

    使用方法

    int socket(int domain, int type, int protocol);

    在参数表中,domain指定使用何种的地址类型,比较常用的有:

    PF_INET, AF_INET: Ipv4网络协议;

    PF_INET6, AF_INET6: Ipv6网络协议。

    type参数的作用是设置通信的协议类型,可能的取值如下所示:

    SOCK_STREAM:提供面向连接的稳定数据传输,即TCP协议。

    OOB:在所有数据传送前必须使用connect()来建立连接状态。

    SOCK_DGRAM:使用不连续不可靠的数据包连接。

    SOCK_SEQPACKET:提供连续可靠的数据包连接。

    SOCK_RAW:提供原始网络协议存取。

    SOCK_RDM:提供可靠的数据包连接。

    SOCK_PACKET:与网络驱动程序直接通信。

    参数protocol用来指定socket所使用的传输协议编号。这一参数通常不具体设置,一般设置为0即可。

    使用说明

    1、介绍

    当你进入 UNIX   的神秘世界后,立刻会发现越来越多的东西难以理解。对于大多数人来说,BSD socket 的概念就是其中一个。这是一个很短的教程来解释他们是什么、他们如何工作并给出一些简单的代码来解释如何使用他们。

    2、类比 (什么是 socket ?)

    socket 是进行程序间通讯(IPC)的 BSD 方法。这意味着 socket 用来让一个进程和其他的进程互通信息,就象我们用电话来和其他的人交流一样。

    用电话来比喻是很恰当的,我们在后面将一直用电话这个概念来描叙 socket 。

    3、装上你的新电话(怎样侦听?)

    一个人要能够收到别人打给他的电话,首先他要装上一门电话。同样,你必须先建立 socket 以侦听线路。这个过程包含几个步骤。首先,你要建立一个新的 socket,就象先装上电话一样。socket() 命令就完成这个工作。

    因为 sockets 有几种类型,你要注明你要建立什么类型的。你要做一个选择是 socket 的地址格式。如同电话有音频和脉冲两种形式一样,socket 有两个最重要的选项是 AF_UNIX 和 AF_INET。AF_UNIX 就象 UNIX 路径名一样识别 sockets。这种形式对于在同一台机器上的 IPC 很有用。而 AF_INET 使用象 192.9.200.10 这样被点号隔开的四个十进制数字的地址格式。除了机器地址以外,还可以利用端口号来允许每台机器上的多个 AF_INET socket。我们这里将着重于 AF_INET 方式,因为他很有用并广泛使用。

    另外一个你必须提供的参数是 socket 的类型。两个重要的类型是 SOCK_STREAM 和 SOCK_DGRAM。 SOCK_STREAM表明数据象字符流一样通过 socket 。而 SOCK_DGRAM 则表明数据将是数据报(datagrams)的形式。我们将讲解 SOCK_STREAM sockets,他很常见并易于使用。

    在建立 socket 后,我们就要提供 socket 侦听的地址了。就象你还要个电话号码来接电话一样。bind() 函数来处理这件事情。

    SOCK_STREAM sockets 让连接请求形成一个队列。如果你忙于处理一个连接,别的连接请求将一直等待到该连接处理完毕。listen() 函数用来设置最大不被拒绝的请求数(一般为5个)。一般最好不要使用 listen() 函数。

    下面的代码说明如何利用 socket()、 bind() 和 listen() 函数建立连接并可以接受数据。

    /* code to establish a socket; originally from bzs@bu-cs.bu.edu

    */

    int establish(unsigned short portnum)

    { char myname[MAXHOSTNAME+1];

    int s;

    structsockaddr_insa;

    struct hostent *hp;

    memset(&sa, 0, sizeof(struct sockaddr_in)); /* clear our address */

    gethostname(myname, MAXHOSTNAME); /* who are we? */

    hp= gethostbyname(myname); /* get our address info */

    if (hp == NULL) /* we don't exist !? */

    return(-1);

    sa.sin_family= hp->h_addrtype; /* this is our host address */

    sa.sin_port= htons(portnum); /* this is our port number */

    if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0) /* create socket */

    return(-1);

    if (bind(s,&sa,sizeof(structsockaddr_in)) < 0) {

    close(s);

    return(-1); /* bind address to socket */

    }

    listen(s, 3); /* max # of queued connects */

    return(s);

    }

    在建立完 socket 后,你要等待对该 socket 的调用了。accept() 函数为此目的而来。调用 accept() 如同在电话铃响后提起电话一样。Accept() 返回一个新的连接到调用方的 socket 。

    下面的代码演示使用是个演示。

    /* wait for a connection to occur on a socket created with establish()

    */

    int get_connection(int s)

    { int t; /* socket of connection */

    if ((t = accept(s,NULL,NULL)) < 0) /* accept connection if there is one */

    return(-1);

    return(t);

    }

    和电话不同的是,在你处理先前的连接的时候,你还可以接受调用。为此,一般用 fork 来处理每个连接。下面的代码演示如何使用 establish() 和 get_connection() 来处理多个连接。

    #include /* obligatory includes */

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #define PORTNUM 50000 /* random port number, we need something */

    void fireman(void);

    void do_something(int);

    main()

    { int s, t;

    if ((s= establish(PORTNUM)) < 0) { /* plug in the phone */

    perror("establish");

    exit(1);

    }

    signal(SIGCHLD, fireman); /* this eliminates zombies */

    for (;;) { /* loop for phone calls */

    if ((t= get_connection(s)) < 0) { /* get a connection */

    if (errno == EINTR) /* EINTR might happen on accept(), */

    continue; /* try again */

    perror("accept"); /* bad */

    exit(1);

    }

    switch(fork()) { /* try to handle connection */

    case -1 : /* bad news. scream and die */

    perror("fork");

    close(s);

    close(t);

    exit(1);

    case 0 : /* we're the child, do something */

    close(s);

    do_something(t);

    exit(0);

    default : /* we're the parent so look for */

    close(t); /* another connection */

    continue;

    }

    }

    }

    /* as children die we should get catch their returns or else we get

    * zombies, A Bad Thing. fireman() catches falling children.

    */

    void fireman(void)

    {

    while (waitpid(-1, NULL, WNOHANG) > 0)

    ;

    }

    /* this is the function that plays with the socket. it will be called

    * after getting a connection.

    */

    void do_something(int s)

    {

    /* do your thing with the socket here

    :

    :

    */

    }

    4、拨号 (如何调用 socket)

    现在你应该知道如何建立 socket 来接受调用了。那么如何调用呢?和电话一样,你要先有个电话。用 socket() 函数来完成这件事情,就象建立侦听的 socket 一样。

    在给 socket 地址后,你可以用 connect() 函数来连接侦听的 socket 了。下面是一段代码。

    int call_socket(char *hostname, unsigned short portnum)

    { struct sockaddr_in sa;

    struct hostent *hp;

    int a, s;

    if ((hp= gethostbyname(hostname)) == NULL) { /* do we know the hosts */

    errno= ECONNREFUSED; /* address? */

    return(-1); /* no */

    }

    memset(&sa,0,sizeof(sa));

    memcpy((char *)&sa.sin_addr,hp->h_addr,hp->h_length); /* set address */

    sa.sin_family= hp->h_addrtype;

    sa.sin_port= htons((u_short)portnum);

    if ((s= socket(hp->h_addrtype,SOCK_STREAM,0)) 0) {

    bcount += br; /* increment byte counter */

    buf += br; /* move buffer ptr for next read */

    }

    else if (br < 0) /* signal an error to the caller */

    return(-1);

    }

    return(bcount);

    }

    相同的函数也可以写数据,留给我们的读者吧。

    5、谈话

    6、挂起(结束)

    和你通过电话和某人交谈后一样,你要在 socket 间关闭连接。一般 close() 函数用来关闭每边的 socket 连接。如果一边的已经关闭,而另外一边却在向他写数据,则返回一个错误代码。

    7、世界语(交流的语言很重要)

    现在你可以在机器间联络了,可是要小心你所说的话。许多机器有自己的方言,如 ASCII 和 EBCDIC。更常见的问题是字节顺序问题。除非你一直传输的都是文本,否则你一定要注意这个问题。幸运的是,人们找出了解决的办法。

    在很久以前,人们争论哪种顺序更“正确”。现在必要时有相应的函数来转换。其中有 htons()、ntohs()、htonl() 和 ntohl()。在传输一个整型数据前,先转换一下。

    i= htonl(i);

    write_data(s, &i, sizeof(i));

    在读数据后,再变回来。

    read_data(s, &i, sizeof(i));

    i= ntohl(i);

    如果你一直坚持这个习惯,你将比别人少出错的机会。

    8、未来在你的掌握了(下一步?)

    就用我们刚才讨论的东西,你就可以写自己的通讯程序了。和对待所有的新生事物一样,最好还是看看别人已经做了些什么。这里有许多关于 BSD socket 的东西可以参考。

    请注意,例子中没有错误检查,这在“真实”的程序中是很重要的。你应该对此充分重视。

    内容声明

    1、本网站为开放性注册平台,以上所有展示信息均由会员自行提供,内容的真实性、准确性和合法性均由发布会员负责,本网站对此不承担任何法律责任。

    2、网站信息如涉嫌违反相关法律规定或侵权,请发邮件至599385753@qq.com删除。

    Copyright © 趣爱秀