网络编程——TCP

news2024/11/26 16:43:34

socket

在这里插入图片描述

socket类型

流式套接字(SOCK_STREAM) TCP
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复、无丢失、无失序的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。
数据报套接字(SOCK_DGRAM) UDP
提供无连接服务、不可靠。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。
原始套接字(SOCK_RAW)
可以对较低层次协议如IP、ICMP直接访问。

函数接口

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */

int socket(int domain, int type, int protocol);
作用:创建一个通信的节点(创建一个socket文件描述符)
参数:
    domain:
        AF_UNIX, AF_LOCAL   本地通信(进程的第七种通信)            unix(7)
        AF_INET             借助ipv4进行通信			          	ip(7)
        AF_INET6            借助ipv6进行通信          			ipv6(7)
    type:
        SOCK_STREAM:用TCP进行通信
        SOCK_DGRAM:使用UDP进行通信
    protocol: 0
        
返回值:
    成功返回一个socket文件描述符
    失败的话返回-1

TCP的编程流程

在这里插入图片描述
connect

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
作用:客户端的socket连接服务器
参数:
    sockfd:socket接口返回的文件描述符
    addr:服务器的地址,帮助文档的接收在bind里,
    protocol: 0
        
返回值:

第二个参数struct sockaddr *addr的解释
struct sockaddr {
   sa_family_t sa_family;   //同socket接口的domain参数
   char        sa_data[14];
}

上面的接口类型只是socket接口族为了兼容多种协议,定义的一个通用的结构体,实际编程的时候,
需要你根据具体的协议类型,使用具体协议的结构体,对于ipv4来讲,需要看ip的第7个手册(man 7 ip)
就能得到下面这个地址

struct sockaddr_in {
   sa_family_t    sin_family; /* address family: AF_INET */
   in_port_t      sin_port;   /* 端口:网络字节序 */
   struct in_addr sin_addr;   /* IP地址:网络字节序 */
};

/* Internet address. */
struct in_addr {
   uint32_t       s_addr;     /* ip地址:网络字节序 */
};

addrlen:
    地址的长度

返回值:0 -1

recv/send

#include <sys/types.h>
#include <sys/socket.h>

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
作用:接收网络的数据
参数:
    sockfd:文件描述符
    buf:数据的存放缓冲区
    len:buf缓冲区的最大长度
    flags:默认填0 阻塞接收
返回值:
    成功会返回实际接收到的字节个数
    失败返回-1
    如果返回0的话,代表对端退出

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
作用:发送网络的数据
参数:
    sockfd:文件描述符
    buf:数据的发送缓冲区
    len:发的缓冲区大小
    flags:默认填0
    
返回值:
    成功会返回实际发送成功的字节个数
    失败返回-1

bind

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
作用:绑定服务器地址(只允许绑定本机器的网卡地址)
参数:
sockfd:描述符
addr:代表的是本机的IP地址和端口
addrlen:地址的长度

返回值:0 -1

listen

int listen(int sockfd, int backlog);
作用:监听socket连接
参数:
    sockfd:描述符
    backlog:同时能处理的客户端的个数,随便赋值  5 10 15
返回值:
    0 -1

accept

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
作用:接收一个客户端的连接,它是一个阻塞接口,直到有客户端连入的时候,会退出阻塞
参数:
    sockfd:服务器的描述符
    addr:入参(你传入,接口给你赋值)
    addrlen:地址的长度
返回值:
    错误-1
    成功的话,会返回一个新的描述符,这个描述符代表的是客户端的一条链路

实例代码

客户端:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>

#define N 64

int main(int argc, char *argv[])
{
    if(argc < 3)
    {
        printf("usage:%s <ip> <port>\n", argv[0]);
        return -1;
    }

    // 0定义变量
    int sockfd;
    char buf[N];
    int addrlen = sizeof(struct sockaddr);
    struct sockaddr_in serveraddr;

    // 1创建一个套接字--socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0){
        perror("socket err");
        exit(-1);
    }

    // 2指定服务器地址--sockaddr_in
    bzero(&serveraddr, addrlen);
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    // 3连接服务器--connect
    if(connect(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0){
        perror("connect err");
        exit(-1);
    }

    // 4收发数据--recv/send
    while (1) {
        gets(buf);
        if(strcmp(buf, "quit") == 0){
            break;
        }
        send(sockfd, buf, N, 0);

        //接收服务器的消息
        bzero(buf, N);
        int len = recv(sockfd, buf, N, 0);
        if(len < 0)
        {
            perror("recv err");
            break;
        }
        else if(len == 0)
        {
            printf("server exit\n");
            break;
        }
        else
        {
            printf("recv server = %s\n", buf);
        }
    }

    // 5关闭连接--close
    close(sockfd);
}

服务器

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <netinet/ip.h> /* superset of previous */
#include <string.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    //创建套接字
    int serverfd = socket(AF_INET, SOCK_STREAM, 0);
    if(serverfd < 0)
    {
        perror("socket err");
        return -1;
    }

    //绑定自己的地址
    struct sockaddr_in myaddr;
    socklen_t addrlen = sizeof(myaddr);

    memset(&myaddr, 0, addrlen);
    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(8888);
#if 0    
    myaddr.sin_addr.s_addr = inet_addr("192.168.51.193");
#else
    myaddr.sin_addr.s_addr = INADDR_ANY;
#endif
    int ret = bind(serverfd, (struct sockaddr *)&myaddr, addrlen);
    if(ret < 0)
    {
        perror("bind err");
        return -1;
    }

    //启动监听
    ret = listen(serverfd, 5);
    if(ret < 0)
    {
        perror("bind err");
        return -1;
    }

    //接收客户端的连接
    //定义代表客户端的结构体变量
    struct sockaddr_in cliaddr;
    int clifd = accept(serverfd, (struct sockaddr *)&cliaddr, &addrlen);
    if(clifd < 0)
    {
        perror("accept err");
        return -1;
    }

    printf("新的连接过来了\n");
    printf("ip = %s, port = %d\n", inet_ntoa(cliaddr.sin_addr), \
                            ntohs(cliaddr.sin_port)); 

#define N 64    
    char buf[N] = {0};
    while (1)
    {
        //接收客户端的消息,如果客户端退出的话,服务器也退出
        //接收服务器的消息
        bzero(buf, N);
        int len = recv(clifd, buf, N, 0);
        if(len < 0)
        {
            perror("recv err");
            break;
        }
        else if(len == 0)
        {
            printf("client exit\n");
            break;
        }
        else
        {
            //回发给客户端
            printf("recv client = %s\n", buf);
            send(clifd, buf, N, 0);
        }
    }
    
    close(clifd);
    close(serverfd);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1632141.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学习STM32第二十天

低功耗编程 一、修改主频 STM32F4xx系列主频为168MHz&#xff0c;当板载8MHz晶振时&#xff0c;系统时钟HCLK满足公式 H C L K H S E P L L N P L L M P L L P HCLK \frac{HSE \times PLLN}{PLLM \times PLLP} HCLKPLLMPLLPHSEPLLN​&#xff0c;在文件stm32f4xx.h中可修…

寝室快修|基于SprinBoot+vue的贵工程寝室快修小程序(源码+数据库+文档)

贵工程寝室快修目录 目录 基于SprinBootvue的贵工程寝室快修小程序 一、前言 二、系统设计 三、系统功能设计 1学生信息管理 2 在线报修管理 3公告信息管理 4论坛信息管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&a…

基于SpringBoot+Vue校园竞赛管理系统的设计与实现

项目介绍&#xff1a; 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;竞赛信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行…

Android 学习 鸿蒙HarmonyOS 4.0 第二天(项目结构认识)

项目结构认识 和 了解&#xff1a; 工程目录下的结构如下&#xff1a; 首先能看到有两个.开头的文件&#xff0c;分别是.hvigor 和 .idea。这两个文件夹都是与构建有关系的&#xff0c; 如果你开发过安卓app&#xff0c;构建完会生成一个apk安装包&#xff0c;鸿蒙则是生成hap…

IDEA新版本创建Spring项目只能勾选17和21却无法使用Java8的完美解决方案

想创建一个springboot的项目&#xff0c;使用Spring Initializr创建项目时&#xff0c;发现版本只有17&#xff5e;21&#xff0c;无法选择Java8。 我们知道IDEA页面创建Spring项目&#xff0c;其实是访问spring initializr去创建项目。我们可以通过阿里云国服间接创建Spring项…

MATLAB 运算符

MATLAB 运算符 运算符是一个符号&#xff0c;告诉编译器执行特定的数学或逻辑操作。MATLAB设计为主要在整个矩阵和数组上运行。因此&#xff0c;MATLAB中的运算符既可以处理标量数据&#xff0c;也可以处理非标量数据。MATLAB允许以下类型的基本运算- 算术运算符 关系运算符…

拥抱数字化转型:电子招标系统平台的革新之路

随着信息技术的飞速发展&#xff0c;传统的采购和招标方式正逐渐被数字化解决方案所取代。电子招标系统平台作为这一转型的关键工具&#xff0c;正在全球范围内被越来越多的企业和政府机构所采纳。本文给大家简单介绍下电子招标系统平台的概念、优势以及如何选择一个合适的平台…

采用前后端分离Vue,Ant-Design技术开发的(手麻系统成品源码)适用于三甲医院

开发环境 技术架构&#xff1a;前后端分离 开发语言&#xff1a;C#.net6.0 开发工具&#xff1a;vs2022,vscode 前端框架&#xff1a;Vue,Ant-Design 后端框架&#xff1a;百小僧开源框架 数 据 库&#xff1a;sqlserver2019 系统特性 麻zui、护理、PACU等围术期业务全覆…

【实时数仓架构】方法论(未完)

笔者不是专业的实时数仓架构&#xff0c;这是笔者从其他人经验和网上资料整理而来&#xff0c;仅供参考。写此文章意义&#xff0c;加深对实时数仓理解。 一、实时数仓架构技术演进 1.1、四种架构演进 1&#xff09;离线大数据架构 一种批处理离线数据分析架构&#xff0c;通…

【大学生电子竞赛题目分析】——2023年H题《信号分离装置》

今年的大赛已临近落幕&#xff0c;笔者打算陆续对几个熟悉领域的题目作一番分析与讨论&#xff0c;今天首先分析H题。 网上有一些关于H题的分析&#xff0c;许多都是针对盲信号分析的。然而本题具有明确的信号频率范围&#xff0c;明确的信号可能频率&#xff0c;明确的信号波…

分布式与一致性协议之Paxos算法(三)

Paxos算法 兰伯特关于Multi-Paxos的思考 领导者 我们可以通过引入领导者(Leader)节点来解决第一个问题。也就是说将领导者节点作为唯一提议者&#xff0c;如图所示。这样就不存在多个提议者同时提交提案的情况&#xff0c;也就不存在提案冲突的情况了。这里补充一点:在论文中…

数字化技术可以促进中国企业创新吗?

数字化技术可以显著促进中国企业的创新。数字化技术&#xff0c;包括人工智能&#xff08;AI&#xff09;、区块链&#xff08;Blockchain&#xff09;、云计算&#xff08;Cloud computing&#xff09;、大数据&#xff08;big Data&#xff09;等&#xff0c;被称为ABCD技术&…

精准测试-Vue前端调用链影响变更分析之一

Vue前端调用链影响变更分析之一 一、背景二、工具调研1、 工具介绍&#xff1a;2、工具使用 三、工具落地集成方案&#xff08;待后续补充&#xff09;变更影响较为简单的实现变更影响较为复杂的实现1、全局关系数据库的构建2、变更影响的简单实现3、变更影响的复杂实现 一、背…

Detla lake with Java--入门

最近在研究数据湖&#xff0c;虽然不知道研究成果是否可以用于工作&#xff0c;但我相信机会总是留给有准备的人。 数据湖尤其是最近提出的湖仓一体化概念&#xff0c;很少有相关的资料&#xff0c;目前开源的项目就三个&#xff0c;分别是hudi, detla lake, iceberg。最终选择…

二维码门楼牌管理应用平台建设:档案管理的新篇章

文章目录 前言一、二维码门楼牌管理应用平台概述二、阵地档案管理的现状与挑战三、二维码门楼牌管理应用平台在阵地档案管理中的优势四、二维码门楼牌管理应用平台的建设与实施五、二维码门楼牌管理应用平台的未来发展六、结论 前言 随着信息技术的飞速发展&#xff0c;二维码…

如何下载AndroidStudio旧版本

文章目录 1. Android官方网站2. 往下滑找到历史版本归档3. 同意软件下载条款协议4. 下载旧版本Androidstudio1. Android官方网站 点击 Android官网AS下载页面 https://developer.android.google.cn/studio 进入AndroidStuido最新版下载页面,如下图: 2. 往下滑找到历史版本归…

无人机+集群组网+单兵图传:空地一体化组网技术详解

空地一体化组网技术是一种结合了无人机、集群自组网和单兵图传等多种技术的先进通信解决方案。这种技术方案的主要目的是在前线事故现场和后方指挥中心之间建立一个高效、稳定的通信链路&#xff0c;以确保信息的实时传输和指挥的顺畅进行。 首先&#xff0c;前端视频采集部分&…

视频美颜SDK与主播美颜工具的技术原理与应用场景分析

在直播视频领域中&#xff0c;视频美颜SDK和主播美颜工具发挥着至关重要的作用。本文将探讨这些工具的技术原理及其在不同应用场景中的应用。 一、视频美颜SDK的技术原理 1.1 图像处理技术 视频美颜SDK的核心技术之一是图像处理技术。根据用户设定的美颜参数进行相应的调整。…

【办公类-22-13】周计划系列(5-5)“周计划-05 周计划表格内教案部分“节日”清空改成“节日“” (2024年调整版本)Win32

背景需求&#xff1a; 本学期19周&#xff0c;用了近10周的时间&#xff0c;终于把周计划教案部分的内容补全了&#xff08;把所有教案、反思的文字都撑满一个单元格&#xff09;&#xff0c; 一、原始教案 二、新模板内的教案 三、手动添加文字后的样式&#xff08;修改教案…

后端学习记录~~JavaSE篇(Module08-异常 上 )

总览&#xff1a; Java概述&#xff1a; 思维导图文件在本人个人主页上-----资源模块 资源详情&#xff08;免费下载&#xff09;&#xff1a;Java学习思维导图异常篇资源-CSDN文库https://download.csdn.net/download/m0_61589682/89238330 整体展示&#xff1a;