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

Posted 夜色魅影

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;

以上是关于TCP/IP网络编程 学习笔记_2 --套接字类型与协议设置的主要内容,如果未能解决你的问题,请参考以下文章

TCP/IP学习笔记之IP协议

DAY18Socket编程,ROSE建模与TCP/IP的学习笔记

学习笔记HTTP协议简介

java学习笔记之网络编程

Linux运维之道之网络基础学习笔记1.1

tcp/ip 协议学习笔记   章一