美文网首页
TCP网络编程

TCP网络编程

作者: 潘雪雯 | 来源:发表于2020-05-07 22:31 被阅读0次

socket介绍

网络层的IP地址可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(IP地址,协议,端口)就可以标识网络的进程。
使用TCP/IP协议的应用程序通常采用应用编程接口:套接字(socket),采用open-->write/read-->close模式实现。


TCP交互流程
  1. 服务器根据地址类型(ipv4,ipv6)、socket类型,协议创建socket。
  2. 服务器为socket绑定IP地址和端口号
  3. 服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开
  4. 客户端创建socket
  5. 客户端打开socket,根据服务器IP地址和端口号试图连接服务器socket
  6. 服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时socket进入阻塞状态,即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端连接请求。
  7. 客户端连接成功,向服务器发送连接状态信息
  8. 服务器accept方法发挥,连接成功
  9. 客户端向socket写入信息
  10. 服务器读取信息
  11. 客户端关闭
  12. 服务器端关闭

socket接口函数

  • socket函数用于创建一个socket描述符,唯一标识一个socket。socket函数有3个参数分别如下所述:
  1. domain:即协议域,又称协议族(family),如AF_INETAF_INET6AF_LOCAL。决定了socket的地址类型,在通信中必须采用对应的地址。如AF_INET决定了要用ipv4地址(32位)与端口号(16位)的组合。
  2. type: 指定socket类型。常见的socket类型有:SOCK_STREAM表示提供面向连接的稳定数据传输、SOCK_DGRAM表示使用不连续、不可靠的数据包连接。
  3. protocal:指定协议。常用的协议有IPPROTO_TCP对应TCP传输协议、IPPROTO_UDP对应UDP传输协议、IPPROTO_SCTP对应STCP传输协议、IPPROTO_TIPC对应TIPC传输协议。
    若protocal为0 ,会自动选择type类型对应的默认协议。
int socket(AF_INET, SOCK_STREAM, 0)

4)函数返回值:若失败就会返回-1,成功会返回新创建的套接字的描述符。为整数类型的值。

  • bind函数
    该函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。
    bind函数原型
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函数的3个参数分别如下描述:

  1. sockfd:即socket描述字,是通过socket()函数创建来唯一标识一个socket的,bind()函数就是将给这个描述字绑定一个名字。
  2. addr: 是一个const struct sockaddr 指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket 时的地址协议族的不同而不同。是一个结构体类型指针。
    其中
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY)中参数INADDR_ANY用于多网卡的机器上,多个IP都可以连上。若设置为servaddr.sin_addr.s_addr = inet_addr("192.168.1.1")*则表示只能连接到192.168.1.1。
    image.png
  3. addrlen:对应的是地址的长度。
  4. 函数返回值:若函数执行成功,返回值为0,反之为SOCKET_ERROR
  • listen和connect函数
    调用listen()来监听socket。listen和connect函数原型是:
int listen(int sockfd, int backlog);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。
connect函数的第一个参数即为要监听的socket描述字,第二个参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用
connect函数建立于TCP服务器的连接。

  • accept函数
    TCP客户端调用connect()之后会向TCP服务器发送一个连接请求。TCP服务器监听到这个请求后,会调用accept()函数接收请求,这样连接就建立起来了。accept的函数原型
int accept(int sockfd, const struct sockaddr *addr, socklen_t *addrlen)

accept函数的第一个参数即为服务器的socket描述字,第二个参数为struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。若accept成功,则其返回值由内核自动生成一个全新的描述符,代表与返回客户的TCP连接。

  1. read和write函数
    网络I/O操作常用的是read()和write()。read()的函数原型是:
ssize_t read(int fd,void *buf,size_t count);

read()函数负责从fd中读取内容。当读取成功时,read()返回实际所读的字节数,返回值0表示已经读到文件的结束,小于0表示出现错误,若错误为EINRT表示在读的时候出现中断错误。。3个参数分别是:1)fd表示socket描述字 2) buf表示缓冲区 3) count表示缓冲区长度。
write()的函数原型是:

ssize_t write(int fd,void *buf,size_t count);

writed()函数将buf中的nbytes字节内容写入文件描述符fd成功时返回写的字节数,失败时返回-1,并设置errno变量。返回值大于0,表示写了部分或全部数据;返回值小于0表示出现错误,若错误为EINRT表示在写的时候出现中断错误。

  • close函数
    关闭相应的socket描述字。close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。

代码

  • 服务器端server.cpp
  1. 创建socket,并给serveraddress赋值
    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
        printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 使用自己的 ip 地址
    servaddr.sin_port = htons(1101);
  1. 绑定socket和端口号
    if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
        printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }
  1. 监听端口号
if( listen(listenfd, 10) == -1){
        printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }

<- -----------------------服务器的准备工作完成--------------------------------- ->

  • 客户端client.cpp
  1. 创建socket
if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
        return 0;
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(1101);
  1. 连接指定计算机端口
if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
        printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }
  1. 发送数据给服务器或向socket写入数据
printf("send msg to server: \n");
    fgets(sendline, 4096, stdin);
    if( send(sockfd, sendline, strlen(sendline), 0) < 0){
        printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }
    close(sockfd);
  1. 服务器接收来自客户端的连接请求从socket中读取字符accept()
printf("======waiting for client's request======\n");
    while(1){
        if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){
            printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
            continue;
        }
  1. 服务器从socket中读取数据recv()
        n = recv(connfd, buff, MAXLINE, 0);
        buff[n] = '\0';
        printf("recv msg from client: %s\n", buff);
        close(connfd);
    }
    close(listenfd);
image.png
如果两次连接的间隔太短不到两个MSL等待时间(MSL指一个片段在网络中最大的存货时间),也就是四次挥手没有完成没有正常关闭,会出现bind socket error: Address already in use(errno: 98)

相关文章

  • 网络基础介绍

    网络编程的两种 TCP socket编程,是网络编程的主流。之所以叫Tcp socket编程,是因为底层是基于Tc...

  • Python TCP编程

    Python网络编程之TCP 一、TCP协议 TCP协议,传输控制协议(Transmission Control ...

  • Linux网络编程篇之ICMP协议分析及ping程序实现

    Linux网络编程系列: Linux网络编程篇之Socket编程预备知识 Linux网络编程篇之TCP协议分析及聊...

  • socket通讯编程

    这一块属于网络编程,主要是学习TCP/IP四层的网络体系结构,学习TCP编程和UDP编程。 java.net中 一...

  • socket网络编程-基础知识

    什么是网络编程 网络编程的本质是两个设备之间的数据交换。 Socket、TCP/IP和Udp TCP 传输控制协议...

  • Node.js中的网络编程

    实验简介 此实验主要讲解TCP和UDP的网络编程,net模块提供了一个异步网络包装器,用于TCP网络编程,它包含了...

  • 网络编程面试题总结

    网络编程知识→ tcp、udp、http、https 等常用协议tcp协议:传输控制协议(TCP,Transmis...

  • Golang网络编程TCP连接

    Golang网络编程 TCP编程编写服务端package mainimport ( "bufio" "fmt"...

  • 网络编程-TCP

    1.tcp的相关介绍 udp通信模型: udp通信模型中,在通信开始之前,不需要建立相关的链接,只需要发送数据即可...

  • 网络编程

    要想实现网络传输,需要考虑的问题有哪些? 1.1 如何才能准确的定位网络上的一台主机?1.2 如何才能进行可靠的、...

网友评论

      本文标题:TCP网络编程

      本文链接:https://www.haomeiwen.com/subject/xpxnghtx.html