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 }
ok,大功完成。怎么样很好玩吧!