zoukankan      html  css  js  c++  java
  • TCP/IP网络编程系列之二(初级)

    套接字类型与协议设置

       我们先了解一下创建套接字的那个函数 int socket(int domain,int type,int protocol);成功时返回文件描述符,失败时返回-1.其中,domain是套接字使用中的协议族(Protocol Family)信息。type套接字类型里面的数据传输类型信息。protocol计算机通信中使用的协议信息。

    协议族(Protocol Family)

    协议族类型有:

        PE_INET          IPV4

        PE_INET6          IPV6

              PF_LOCAL        本地通信的UNIX协议族

          PF_PACKET        底层套接字的协议族

              PF_IPX         IPX Novell协议族

    套接字类型(Type)

      套接字类型指的是套接字的数据传输方式,通过socket函数的第二个参数传递,只有这样才能决定创建的套接字的数据传输方式。决定了协议族并不能同时决定数据传输方式。也就是说socket函数第一个参数的PF_INET协议族存在多重数据传输方式。

    第一种:面向连接的套接字(SOCK_STREAM)

      如果给第二个参数传递SOCK_STREAM,将创建面向连接的套接字。特点:

    • 套接字连接必须一一对性。
    • 可靠的、按序传递的、基于字节的面向连接的数据传输方式的套接字。

    收发数据的套接字内部有缓冲(buffer),简言之就是字节数组。通过套接字传输的数据将保存到该数组中。因此,收到数据并不意味着马上调用read函数。只要不超过数组容量,则有可能数据填充满缓冲后通过一次read函数调用全部读完,也有可能分成多次调用read函数调用进行读取。也就是说,在面向连接的套接字中,read和write函数调用多次并无太大意义,所以说面向连接的套接字编程不存在数据边界。

    如果套接字缓冲已满是否意味着数据丢失?首先调用read函数从缓冲区读取部分数据,因此,缓冲并不总是满的。但如果read函数读取的速度比接收数据的速度慢,则缓冲有可能被填满,此时套接字无法在接收数据,但即使这样也不会发生数据丢失。因为传输端套接字将停止传输。也就是说,面向连接的套接字会根据接收端的状态传输数据,如果传输出错还会提供重传服务。因此,面向连接的套接字除特殊的情况不会发生数据丢失。

    第二种:面向消息的套接字(SOCK_DGRAM)

      如果给第二个参数传递SOCK_DGRAM,将创建面向消息的套接字。特点:

    • 不可靠的、不按序传递的、以数据的告诉传输为目的的套接字。
    • 传输的数据具有数据边界。

    套接字协议信息

    第三个参数主要用在同一协议族中存在多重传输方式相同的协议,数据传输方式相同,但协议不同。此时靠第三个参数具体指定协议信息。

    简单的例子:

      要求在IPV4协议族中创建面向连接的套接字。其中在TCP/IP网络编程系列之一中创建服务端和客户端的代码,服务端的代码不需要改变,只改变客户端的代码,更改read函数的调用方式。

    TCPClient代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>

    #define MAXSIZE 30
    void Error_Handling(char* message);

    int main(int argc,char* argv[])
    {
        int sock;
        struct  sockaddr_in serverAddr;
        char message[MAXSIZE];
        int str_len=0;
        int idx=0,read_len=0;
        if(argc != 3)
        {
            printf("Usage : %s <IP> <Port> ",argv[0]);
            exit(1);
        }
        sock = socket(PF_INET,SOCK_STREAM,0);
        if(sock == -1)
        {
            Error_Handling("sock() error");
        }
        memset(&serverAddr,0,sizeof(serverAddr));
        serverAddr.sin_family=AF_INET;
        serverAddr.sin_addr.s_addr=inet_addr(argv[1]);
        serverAddr.sin_port=htons(atoi(argv[2]));
        if(connect(sock,(struct sockaddr*)&serverAddr,sizeof(serverAddr))==-1)
        {
            Error_Handling("connect() error");
        }
       
        while(( read_len = read(sock,&message[idx++],1)))
        {
            if(read_len==-1)
            {
                Error_Handling("read() error ");
            }
            str_len+=read_len;
        }
        printf("Message from server : %s ",message);
        printf("Function read call count:%d ",str_len);
        close(sock);
        return 0;
    }

    void Error_Handling(char *message)
    {
        fputs(message,stderr);
        fputc(' ',stderr);
        exit(1);
    }

  • 相关阅读:
    java 查看 class文件编译时使用的编译器版本
    eclipse新建maven工程(web工程)
    U盘插入后电脑提示“使用驱动器F:中的光盘之前需要将其格式化”,该怎么办?(实测有用)
    随笔安装theano的那些故事(亲测有效,附安装包)
    Python学习4Python的交互
    Mysql热备份总结
    php中date()函数的使用
    在linux中用C语言实现ping命令的部分功能
    【转】/etc/sysconfig/目录详解
    python学习(一)
  • 原文地址:https://www.cnblogs.com/tianlangshu/p/6753840.html
Copyright © 2011-2022 走看看