网络编程——TCP

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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

异常处理方式

在定义方法时&#xff0c;首先需要先对参数数据进行合法判断 数据若不合法&#xff0c;使用抛出异常的方式来告诉调用者&#xff0c;传递合法的数据进来 在方法内使用 throw 抛出指定异常对象&#xff0c;throw new XxxException(“异常产生原因”) 创建的是运行时异常&…

ROS学习笔记(14)拉普拉斯变换和PID

0.前提 近些时间在对睿抗的ROS仿真赛进行小组安排&#xff0c;对小组成员进行了一些安排&#xff0c;也要求他们以本次比赛写下自己的比赛经历博客&#xff0c;他们的培训由我来安排和负责&#xff0c;因此我得加吧油&#xff0c;起码保证我的进度得快过他们&#xff0c;才能安…

使用yolov8+QT+onnrunxtime进行开发的注意事项

1、本来想尝试做一个C的yolov8在QT5.15.2的应用&#xff1b; 因此&#xff0c;在实现这个目标的时候&#xff0c;我先用了yolov8自带的export进行导出&#xff0c;使用的代码很简单&#xff0c;如下所示&#xff1a; import os from ultralytics import YOLO# model YOLO(&q…

SpringBoot 快速开始 Dubbo RPC

文章目录 SpringBoot 快速开始 Dubbo RPC下载 Nacos项目启动项目的创建创建主项目接口定义服务的创建Dubbo 服务提供者的创建服务的消费者创建 添加依赖给 Provider、Consumer 添加依赖 开始写代码定义接口在 Provider 中实现在 Consumer 里面使用创建启动类 注册中心配置启动 …

绘唐科技AIGC怎么激活

绘唐科技AIGC怎么激活绘唐科技AIGC怎么激活绘唐科技AIGC怎么激活绘唐科技AIGC怎么激活 这里激活免费3天体验 Docshttps://qvfbz6lhqnd.feishu.cn/wiki/D3YLwmIzmivZ7BkDij6coVcbn7W

架构师技能:技术深度硬实力透过问题看本质--深入分析nginx偶尔502错误根因

以架构师的能力标准去分析每个问题&#xff0c;过后由表及里分析问题的本质&#xff0c;复盘总结经验&#xff0c;并把总结内容记录下来。当你解决各种各样的问题&#xff0c;也就积累了丰富的解决问题的经验&#xff0c;解决问题的能力也将自然得到极大的提升。励志做架构师的…

Spring IOC(二)

1. Bean的定义与获取 1.1 定义Bean 在Spring 中定义Bean的方式主要有三种&#xff1a; 1、基于XML配置文件的方式&#xff08;了解&#xff09;&#xff1a;通常会在配置文件中使用<bean>标签来定义Bean&#xff0c;并设置Bean的属性、依赖关系等信息。 2、基于注解的方…

C语言程序设计(一)

1、指令、程序、软件 2、计算机语言&#xff1a;机器语言、汇编语言、高级语言 高级语言的发展&#xff1a;非结构化语言&#xff08;FORTRAN&#xff09;、结构化语言&#xff08;C语言&#xff09;、面向对象的语言&#xff08;C、面向对象&#xff09; 3、源程序、二进制…

数据可视化在不同行业中有哪些应用?

数据可视化即通过图表的形式将数据的内在信息有逻辑性地呈现给用户&#xff0c;使用户更容易发现数据中蕴藏的规律&#xff0c;找出问题&#xff0c;进而做出决策&#xff1b;另一方面&#xff0c;数据可视化项目也是一张重要的名片&#xff0c;是企业数字化建设效果的呈现。本…

FPGA实现图像处理之【直方图均衡-寄存器版】

FPGA实现直方图统计 一、图像直方图统计原理 直方图的全称为灰度直方图&#xff0c;是对图像每一灰度间隔内像素个数的统计。即对一张图片中每隔二灰度值的像素数量做统计&#xff0c;然后以直方图的形式展现出来。图下的亮暗分布在直方图中就可以一目了然&#xff0c;直方图…

【数据结构与算法】力扣 225. 用队列实现栈

题目描述 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。 实现 MyStack 类&#xff1a; void push(int x) 将元素 x 压入栈顶。int pop() 移除并返回栈顶元…

AI项目二十:基于YOLOv8实例分割的DeepSORT多目标跟踪

若该文为原创文章&#xff0c;转载请注明原文出处。 前面提及目标跟踪使用的方法有很多&#xff0c;更多的是Deepsort方法。 本篇博客记录YOLOv8的实例分割deepsort视觉跟踪算法。结合YOLOv8的目标检测分割和deepsort的特征跟踪&#xff0c;该算法在复杂环境下确保了目标的准…

R语言的基本图形

一&#xff0c;条形图 安装包 install.packages("vcd") 绘制简单的条形图 barplot(c(1,2,4,5,6,3)) 水平条形图 barplot(c(1,2,4,5,6,3),horiz TRUE) 堆砌条形图 > d1<-c("Placebo","Treated") > d2<-c("None",&qu…

linux运行python怎么结束

假如你已经进入到【>>>】&#xff0c;那么输入【quit&#xff08;&#xff09;】&#xff0c;然后按一下回车键即可退出了。 如果是想要关闭窗口的&#xff0c;那么直接在这个窗口上按【ctrld】。

vue2集成ElementUI编写登录页面

目录 1. 整理目录文件&#xff1a; a. app.vue文件如下&#xff1a; b. Login.vue文件如下&#xff1a; c. router/index.js文件如下&#xff1a; d. 删除components中的文件&#xff1a; e. 最终项目目录整理如下&#xff1a; 2. 集成ElementUI编写登录页面 a. 安装El…

Vue3 v3.4之前如何实现组件中多个值的双向绑定?

文章目录 基础代码1. watch2. computed&#xff08;推荐&#xff09; 官方给的例子是关于el-input的&#xff0c;如下。但是input不是所有组件标签都有的属性啊&#xff0c;有没有一种通用的办法呢&#xff1f; <script setup> defineProps({firstName: String,lastName…

Docker容器:搭建LNMP架构

目录 前言 1、任务要求 2、Nginx 镜像创建 2.1 建立工作目录并上传相关安装包 2.2 编写 Nginx Dockerfile 脚本 2.3 准备 nginx.conf 配置文件 2.4 生成镜像 2.5 创建 Nginx 镜像的容器 2.6 验证nginx 3、Mysql 镜像创建 3.1 建立工作目录并上传相关安装包 3.2 编写…

FANUC机器人SOCKET断开KAREL程序编写

一、添加一个.KL文件创建编辑断开指令 添加一个KL文件用来创建karel程序中socket断开指令 二、断开连接程序karel代码 PROGRAM SOC_DIS %COMMENT SOCKET断开 %INCLUDE klevccdf VAR str_input,str_val : STRING[20] status,data_type,int_val : INTEGER rel_val : REALBEGING…

【Linux】文件打包解压_tar_zip

文章目录 &#x1f4d1;引言&#xff1a;一、文件打包压缩1.1 什么是文件打包压缩&#xff1f;1.2 为什么需要文件打包压缩&#xff1f; 二、打包解压2.1 zip2.2 unzip2.3 tar指令 &#x1f324;️全篇小结&#xff1a; &#x1f4d1;引言&#xff1a; 在Linux操作系统中&#…

简单易懂的下载学浪视频教程- 小浪助手

接下来我就教大家如何通过小浪助手&#xff0c;轻松下载你想要下载的学浪app视频 首先准备好小浪助手 工具我已经打包好了&#xff0c;有需要的自己取一下 学浪下载器链接&#xff1a;https://pan.baidu.com/s/1djUmmnsfLEt_oD2V7loO-g?pwd1234 提取码&#xff1a;1234 -…