TCP/IP网络编程 学习笔记_2 --套接字类型与协议设置

什么是协议
先想象一下这样一个情形:如果相隔很远的两个人要展开对话,必须先决定对话方式。如果一方使用电话,那么另一方也只能使用电话,而不是书信。可以说,这里电话就是两人对话的协议,协议是对话中使用的通信规则。拓展到计算机,协议就是为了完成数据交换而定好的约定。

创建套接字
1,先来看看创建套接字的函数:

int socket(int domain, int type, int protocol);
成功返回文件描述符(整型),失败返回-1。
domain:协议族,type:数据传输类型,protocol:具体协议

2,下面再来分别谈谈创建套接字函数各参数意义:

协议族:奶油意大利面和番茄意大利面均属于意大利面的一种,与之类似,套接字中的协议也有分类,每一类别就称作一个协议族。即上面奶油意大利面和番茄意大利面类似协议,意大利面类似协议族。我们常用的协议族是PF_INET(IPv4互联网协议族)。

套接字类型:是指套接字数据传输的方式,下面介绍2种具有代表性的数据传输方式:
一:面向连接的套接字(SOCK_STREAM),这个和两个工人用传送带传输与接收物品类似,它有以下特性:传输过程中数据不会丢失,按序传输数据,没有数据边界,连接必须一一对应。
注释:没有数据边界是指,数据的发送次数与接收次数没有直接关系,不一定要相等。其实现原理就是在发送与接收端各用了个缓冲区,发送与接收端都是只管从缓冲区里取和拿数据,不直接相关。而且就算某个缓冲区满了也不会丢失数据,因为面向连接的套接字会根据接收端的状态来传输数据,如果缓冲区满了,它会自动停止传输。

二:面向消息的套接字(SOCK_DGRAM),这个就类似快递送包裹,有以下特点:强调传输速度不必按序传输,数据可能丢失,每次传输数据大小有限制,有数据边界(传输次数与接收次数要一一对应),不存在连接的概念。

协议:socket()第三个参数就是具体协议的选择,如:

“IPv4协议族中面向连接的套接字”
int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
因为IPv4协议族中面向连接的套接字的具体协议只有一种就是IPPROTO_TCP,所以第三个参数我们也可以简写成0。这种套接字我们称为TCP套接字。

“IPv4协议族中面向消息的套接字”
int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
同上,这里第三个参数也可以写成0。这种套接字我们称为UDP套接字。
 

代码示例
下面是一个tcp套接字的实例,从中就可以看出tcp套接字没有数据边界。

服务端
//
//  main.cpp
//  hello_server
//
//  Created by app05 on 15-7-6.
//  Copyright (c) 2015年 app05. All rights reserved.
//

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

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


int main(int argc, const char * argv[]) {
    int serv_sock;
    int clnt_sock;

    struct sockaddr_in serv_addr;
    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_size;

    char message[] = "Hello World!";

    if(argc != 2)
    {
        printf("Usage:%s <port>\n", argv[0]);
        exit(1);
    }
    /*IPv4协议族中面向连接的套接字(tcp套接字),因为这种类型下的具体协议只有一种(IPPROTO_TCP),
     所以第三个参数可以简写为0*/
    serv_sock = socket(PF_INET, SOCK_STREAM, 0);
    if(serv_sock == -1)
        error_handling("socket() error");

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

    if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)
        error_handling("bind() error");

    if(listen(serv_sock, 5) == -1)
        error_handling("listen() error");

    clnt_addr_size = sizeof(clnt_addr);
    //如果没有收到请求,则不返回,只到有连接请求为止
    clnt_sock = accept(serv_sock, (struct sockaddr*) &clnt_addr, &clnt_addr_size);
    if(clnt_sock == -1)
        error_handling("accept() error");
    //message数组内容一次性发送
    write(clnt_sock, message, sizeof(message));
    close(clnt_sock);
    close(serv_sock);

    return 0;
}
 

客服端
//
//  main.cpp
//  hello_client
//
//  Created by app05 on 15-7-6.
//  Copyright (c) 2015年 app05. All rights reserved.
//

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

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

int main(int argc, const char * argv[]) {
    int sock;
    struct sockaddr_in serv_addr;
    char message[30];
    int str_len = 0;
    int idx = 0, read_len = 0;

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

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

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

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

    //每次只接收一个字节(服务端一次性发送,客服端多次接收,验证tcp套接字没有数据边界)
    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 \n", message);
    printf("Function read call count: %d \n", str_len);
    close(sock);

    return 0;
}
————————————————
版权声明:本文为CSDN博主「夜色魅影」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010223072/article/details/46813651

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值