02-套接字类型与协议设置

参考书籍:《TCP/IP》网络编程,作者【韩】尹圣雨

测试环境:Ubuntu 10.10

GCC版本:4.4.5

 

一、关于协议

        协议就是为了完成数据交换而定好的约定。

二、深入理解创建套接字

        前边已经介绍过创建套接字函数,后续主要解释该函数参数意义。

头文件:#include <sys/socket.h>
函数功能:创建套接字
返回值:成功时返回文件描述符,失败时返回-1
函数原型:int socket(int domain, int type, int protocol);
函数参数:
domain——套接字中使用的协议族(Protocol Family)信息。
type——套接字数据传输类型信息。
protocol——计算机间通信中使用的协议信息。

三、协议族(Protocol Family)

        socket函数第一个参数传递套接字中使用的协议分类信息。此协议信息为协议族,可分为如下几类:

头文件sys/socket.h中声明的协议族部分简介
名称协议族
PF_INETIPv4互联网协议族
PF_INET6IPv6互联网协议族
PF_LOCAL本地通信的UNIX协议族
PF_PACKET底层套接字的协议族
PF_IPXIPX Novell协议族

 

 

 

 

 

 

 

四、套接字类型(Type)

        socket函数的第一个参数PF_INET协议族中也存在多种数据传输方式。套接字的协议族确定后,通过第二个参数套接字类型确定数据具体传输方式

五、套接字类型

        这里主要介绍面向连接的套接字面向消息的套接字这两种数据传输方式。

面向连接的套接字(SOCK_STREAM:流式套接字):

* 传输过程中数据不会消失

* 按序传输数据

* 传输的数据不存在数据边界(发送数据次数不等于接收数据次数)

概括:可靠的、按序传递的、基于字节的面向连接的数据传输方式的套接字

 

面向消息的套接字(SOCK_DGRAM:数据报套接字):

* 强调快速传输而非传输顺序

* 传输的数据可能丢失也可能损坏

* 传输的数据有数据边界

* 限制每次传输的数据大小

概括:不可靠的、不按序传递的、以数据的高速传输为目的的套接字

 

六、协议的最终选择

        socket函数的第三个参数决定了最终采用的协议。

使用场景:同一协议族存在多个数据传输方式相同的协议

如下:

面向连接的数据传输方式——SOCK_STREAM:
int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

面向消息的数据传输方式——SOCK_DGRAM:
int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

七、面向连接的套接字:TCP套接字示例

服务器端代码:

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

void errorHandling(const char* message);

int main(int argc, char* argv[])
{
    int servSock = -1;
    int clntSock = -1;
    
    struct sockaddr_in servAddr;
    struct sockaddr_in clntAddr;
    socklen_t clntAddrSize;

    char message[] = "Hello World!";

    if(2 != argc)
    {
        printf("Usage:%s <port>\n", argv[0]);
        exit(1);
    }

    servSock = socket(PF_INET, SOCK_STREAM, 0);
    if(-1 == servSock)
        errorHandling("socket() error");

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_famliy = AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(atoi(argv[1]));

    if(-1 == bind(servSock, (struct sockaddr*)&servAddr, sizeof(servAddr)))
        errorHandling("bind() error");

    if(-1 == listen(servSock, 5))
        errorHandling("listen() error");

    clntAddrSize = sizeof(clntAddr);
    clntSock = accept(servSock, (struct sockaddr*)&clntAddr, &clntAddrSize);

    if(-1 == clntSock)
        errorHandling("accept() error");

    write(clntSock, message, sizeof(message));
    close(clntSock);
    close(servSock);

    return 0;
}

void errorHandling(const char* message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

客户端代码:

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

void errorHandling(const char* message);

int main(int argc, char* argv[])
{
    int sock = -1;
    struct sockaddr_in servAddr;
    char message[30] = {0};
    int strLen = -1;
    int idx = 0;
    int readLen = 0;

    if(3 != argc)
    {
        printf("Usage: %s <IP> <port>\n", argv[0]);
        exit(1);
    }

    sock = socket(PF_INET, SOCK_STREAM, 0);
    if(-1 == sock)
        errorHandling("socket() error");

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = inet_addr(argv[1]);
    servAddr.sin_port = htons(atoi(argv[2]));

    if(-1 == connect(sock, (struct sockaddr*)&servAddr, sizeof(servAddr)))
        errorHandling("connect() error");

    while(readLen = read(sock, &message[idx++], 1))
    {
        if(readLen == -1)
            errorHandling("read() error");

        strLen += readLen;
    }

    printf("Message from server: %s\n", message);
    printf("Function read call count: %d\n", strLen);
    close(sock);

    return 0;
}

void errorHandling(const char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

运行结果:

分析:

        服务端只发送一次数据,但是客户端可以多次调用read函数获取数据,证明了面向连接套接字传输的数据不存在数据边界特点!

 

 

      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值