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> \n",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\n");
42         }
43         str_len+=read_len;
44     }
45     printf("Message from server : %s \n",message);
46     printf("Function read call count:%d \n",str_len);
47     close(sock);
48     return 0;
49 }
50 
51 void Error_Handling(char *message)
52 {
53     fputs(message,stderr);
54     fputc('\n',stderr);
55     exit(1);
56 }
TCPClient代码

 

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

posted @ 2014-11-23 22:30  Mr.Brian  阅读(1175)  评论(1编辑  收藏  举报