当前位置: 首页 > article >正文

网络编程-TCP

网络通信基础

1、网络通信的协议:TCPUDPIP

2、网络通信模型:七层模型、四层模型

3、网络通信理论:socketIP、端口号、字节序

4、网络IO模型:4种

5、网络超时处理

6、网络的广播、组播、单播

网络通信的特征

(局域网)不同设备在通信时,要求其IP地址必须处于同一网段

网络通信协议
TCP\IP

(传输控制协议\因特网互联协议)

TCP:主要是数据发送数据时,若出现数据发送失败,可控制进行重新发送

IP:用于通信过程的IP地址

UDP

(用户数据报协议)

UDP:没有数据重发机制

TCPUDP
可靠通信不可靠通信
通信效率低通信效率高
面向连接面向非连接
网络通信模型
七层模型四层模型
应用层领导口述一段话
表示层秘书记录口述内容形成信件
会话层将信件放在公司前台应用层领导自己写信放置前台
传输层快递员从前台取件传输层快递员从前台取件
网络层分拣快递理清发送地址网络层分拣快递理清发送地址
数据链路层快递传输过程
物理层将信件送至收件人网络链路层投送快递到收件人
网络通信理论

socket:套接字,特殊的文件描述符,不允许使用open打开

IP:当前所用的IP地址都是32位的点分式,用于区分设备

端口号:2字节的短整型(1~65535)自己写的程序中端口号一般设置大于10000即可,用于区分应用

字节序:在x86体系下,操作系统一般是小端存储模式,对于网络通信一般是大端存储模式

网络通信高级

TCP通信流程
客户端服务器
保证有一台手机int cfd = socket保证有一台手机int sdf = socket
拨打号码connect(cfd)需要绑定一个手机号bind(sfd)
畅聊,相当于收发数据send(cfd)设定手机铃声,用于监视listen(sfd)
挂断电话close(cfd)等待来电,等待客户端连接请求int cfd = accept(sfd)
畅聊,相当于收发数据recv(cfd)
挂断电话close(cfd)close(sfd)
//实现一个客户端给服务器发送 服务器负责接收
//head.h
#ifndef _HEAD_H
#define _HEAD_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#endif 
//服务端
// ./server 1277.0.0.1 10001
int main(int argc, char* argv[])
{
    // 参数1:代表IPV4
    // 参数2:代表TCP
    // 参数3:默认为0,一般不用
    // 返回值:返回服务端的套接字,失败返回-1
    
    // 1、创建套接字
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sfd < 0)
    {
        perror("socket error");
        return -1;
    }
    // 知道创建操作完成
    printf("socket success\n");
    
    // 2、服务端绑定IP地址和端口号
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;	// 地址族IPV4
    addr.sin_port = atoi(argv[2]);	// 设置端口号
    // 将字符串形式的IP地址直接转换成网络地址
    int ret = inet_pton(AF_INET, argv[1], (struct in_addr*)&addr.sin_addr);
    if(ret <= 0)
    {
        perror("inet_pton error");
        return -1;
    }
    
    ret = bind(sfd, (struct sockaddr*)&addr, sizeof(addr));
    if(ret < 0)
    {
        perror("bind error\n");
        return -1;
    }
    // 知道绑定操作完成
    printf("bind success\n");
    
    //3、实现监听操作
    ret = listen(sfd, 2);
    if(ret < 0)
    {
        perror("listen error");
        return -1;
    }
    //知道监听完成
    printf("listen success\n");
    
    //4、等待客户端的连接请求
    struct sockaddr_in cld_addr;	//出参:待会连接客户端的IP端口号
    int len = sizeof(cld_addr);
    
    int cfd = accept(sfd, (struct sockaddr*)&cld_addr, &len);
    if(cfd < 0)
    {
        perror("accept error");
        return -1;
    }
    //知道连接完成
    printf("accept success!\n");
    
    //5、接收客户端的数据
    char buf[100];
    while(1)
    {
        bzero(buf, sizeof(buf));
    	recv(cfd, buf, sizeof(buf)-1, 0);
        
        if(strstr(buf, "quit") != NULL)
        {
            break;
        }
        printf("from %d info is:%s\n", cfd, buf);
    }
    
    //6、关闭套接字
    close(cfd);
    close(sfd);
    
    printf("server closed!\n");
    
    return 0;
}


//客户端
// ./client 127.0.0.1 10001
int main(int argc, char* argv[])
{
    // 1、创建套接字
    int cfd = socket(AF_INET, SOCK_STREAM, 0);
    if(cfd < 0)
    {
        perror("socket error");
        return -1;
    }
    // 知道创建操作完成
    printf("socket success\n");
    
    // 2、向服务端发送连接申请
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;	// 地址族IPV4
    addr.sin_port = atoi(argv[2]);	// 设置端口号
    // 将字符串形式的IP地址直接转换成网络地址
    int ret = inet_pton(AF_INET, argv[1], (struct in_addr*)&addr.sin_addr);
    if(ret <= 0)
    {
        perror("inet_pton error");
        return -1;
    }
    
    ret = connect(cfd, (struct sockaddr*)&addr, sizeof(addr));
    if(ret < 0)
    {
        perror("connect error\n");
        return -1;
    }
    // 知道绑定操作完成
    printf("connect success\n");
    
    //3、向服务端的数据
    char buf[100];
    
    while(1)
    {
        bzero(buf, sizeof(buf));
        fgets(buf, sizeof(buf), stdin);
    	send(cfd, buf, sizeof(buf)-1, 0);
        
        if(strstr(buf, "quit") != NULL)
        {
            break;
        }
    }
    
    close(cfd);
    
    printf("client closed!\n");
    
    return 0;
}
//实现多个客户端给服务端发送请求
//服务端
// ./server 1277.0.0.1 10001

void* handle_client(void* arg)
{
    int cfd = *((int*)arg);

    /* 5、接收客户端的数据 */
    char buf[100];

    while(1)
    {
        bzero(buf, sizeof(buf));
        recv(cfd, buf, sizeof(buf)-1, 0);

        if (strstr(buf, "quit") != NULL)
        {
            printf("client [%d] is quit!\n", cfd);
            close(cfd);
            pthread_exit(NULL);
        }

        if (strlen(buf) != 0)
        {
            printf("from %d info is: %s\n", cfd, buf);
        }
    }

}

// ./server 127.0.0.1 10001
int main(int argc,char *argv[])
{
    /* 1、创建套接字 */
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sfd < 0)
    {
        perror("socket error");
        return -1;
    }

    printf("socket success!\n");


    /* 2、服务端绑定IP地址和端口号 */
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;      // 地址簇IPV4
    addr.sin_port = atoi(argv[2]);  // 设置端口号

    // 将字符串形式的IP地址,直接转换为网络地址
    int ret = inet_pton(AF_INET, argv[1], (struct in_addr*)&addr.sin_addr);
    if (ret <= 0)
    {
        perror("inet_pton error");
        return -1;
    }

    ret = bind(sfd, (struct sockaddr *)&addr, sizeof(addr));
    if (ret < 0)
    {
        perror("bind error!\n");
        return -1;
    }

    printf("bind success!\n");


    /* 3、实现监听操作 */
    ret = listen(sfd, 5);
    if (ret < 0)
    {
        perror("listen error!\n");
        return -1;
    }

    printf("listen success!\n");


    /* 4、等待客户端的连接请求 */
    struct sockaddr_in cld_addr; // 出参: 带回连接客户端的IP和端口号
    int len = sizeof(cld_addr);

    
    // 主循环,接受客户端连接
    int cfd;
    pthread_t thread_id;
    while (1) 
    {
        cfd = accept(sfd, (struct sockaddr *)&cld_addr, &len);
        if (cfd < 0)
        {
            // 当前客户端请求失败后,只报错,不能退出程序
            // 因为其他进程还要进行连接。
            perror("accept error!\n");
        }
        else
        {
            // 连接请求成功后,在多线程中进行读写操作
            printf("client socket = [%d]: accept success!\n", cfd);
            if (pthread_create(&thread_id, NULL, handle_client, (void*)&cfd) != 0) 
            {
                // 如果线程创建失败表明无法与客户端实现数据通信,则将客户端的套接字关闭。
                printf("client socket = [%d]: could not create thread: %s\n", cfd, strerror(errno));
                close(cfd);
            }
        }

        // 分离线程,让线程自主运行

        pthread_detach(thread_id);
    }


    /* 6、关闭套接字 */
    // 这个一般执行不到,因为服务端需要一值运行
    close(cfd);
    close(sfd);

    printf("server closed!\n");

    return 0;
}


http://www.kler.cn/a/331599.html

相关文章:

  • [数据结构] 链表
  • ES搜索原理
  • SQL语句自动加上了LIMIT 10,导致报错
  • javax.net.ssl.SSLPeerUnverifiedException: Hostname 192.168.13.13 not verified:
  • word实现两栏格式公式居中,编号右对齐
  • 设计模式--单例模式【创建型模式】
  • 关于Elastic Search与MySQL之间的数据同步
  • 二、MySQL的数据目录
  • 16.数据结构与算法-串,数组与广义表(串,BF算法,KMP算法)
  • linux第二课:常用命令
  • 828华为云征文|使用Flexus X实例创建FDS+Nginx服务实现图片上传功能
  • 微服务(二)
  • Electron 主进程与渲染进程、预加载preload.js
  • 使用rust实现rtsp码流截图
  • Stable Diffusion绘画 | 来训练属于自己的模型:秋叶训练器使用
  • 爬虫——爬取小音乐网站
  • 土地规划中的公共设施布局:科学规划,赋能土地高效利用的艺术
  • SCoRe: 通过强化学习教导大语言模型进行自我纠错
  • 鸿蒙 HarmonyNext 与 Flutter 的异同之处
  • Python Selenium常用语法汇总(包含XPath语法)
  • Linux命令大全及小例子
  • 【服务器】服务器虚拟化概述
  • 基于PyQt5和SQLite的数据库操作程序
  • NLP任务之预测最后一个词
  • 弄一个动态ip池需要多久进行一次维护
  • linux:详解nohup命令