• 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函数的调用方式。

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 #include <unistd.h>
     5 #include <arpa/inet.h>
     6 #include <sys/socket.h>
     7 
     8 #define MAXSIZE 30
     9 void Error_Handling(char* message);
    10 
    11 int main(int argc,char* argv[])
    12 {
    13     int sock;
    14     struct  sockaddr_in serverAddr;
    15     char message[MAXSIZE];
    16     int str_len=0;
    17     int idx=0,read_len=0;
    18     if(argc != 3)
    19     {
    20         printf("Usage : %s <IP> <Port> 
    ",argv[0]);
    21         exit(1);
    22     }
    23     sock = socket(PF_INET,SOCK_STREAM,0);
    24     if(sock == -1)
    25     {
    26         Error_Handling("sock() error");
    27     }
    28     memset(&serverAddr,0,sizeof(serverAddr));
    29     serverAddr.sin_family=AF_INET;
    30     serverAddr.sin_addr.s_addr=inet_addr(argv[1]);
    31     serverAddr.sin_port=htons(atoi(argv[2]));
    32     if(connect(sock,(struct sockaddr*)&serverAddr,sizeof(serverAddr))==-1)
    33     {
    34         Error_Handling("connect() error");
    35     }
    36     
    37     while(( read_len = read(sock,&message[idx++],1)))
    38     {
    39         if(read_len==-1)
    40         {
    41             Error_Handling("read() error
    ");
    42         }
    43         str_len+=read_len;
    44     }
    45     printf("Message from server : %s 
    ",message);
    46     printf("Function read call count:%d 
    ",str_len);
    47     close(sock);
    48     return 0;
    49 }
    50 
    51 void Error_Handling(char *message)
    52 {
    53     fputs(message,stderr);
    54     fputc('
    ',stderr);
    55     exit(1);
    56 }
    TCPClient代码

    ok,大功完成。怎么样很好玩吧!

    取法乎上,仅得其中;取法乎中,仅得其下;取法乎下,一无所得。
  • 相关阅读:
    程序员有哪些发展方向
    Mysql Join语法解析与性能分析
    jQuery过滤性选择器
    jQuery 基础选择器
    CSS布局模型
    CSS 盒子模型
    CSS 的继承、层叠和特殊性
    java 集合框架(一)
    从客户端中检测到有潜在危险的 Request.Form 值
    线程的一些问题
  • 原文地址:https://www.cnblogs.com/Brianlv/p/4117343.html
Copyright © 2020-2023  润新知