Linux网络编程:socket、客户端服务器端使用socket通信(TCP)

news2024/9/27 21:18:36

socket

socket(套接字),用于网络中不同主机间进程的通信。

socket是一个伪文件,包含读缓冲区、写缓冲区。

socket必须成对出现。

socket可以建立主机进程间的通信,但需要协议(IPV4、IPV6等)、port端口、IP地址。


客户端服务端socket网络通信步骤(TCP)

服务器端:

        (1)创建流式socket套接字。

                a)此socket套接字一直用于后续的监听连接。

                b)socket函数。

        (2)绑定本机IP地址和port。

                b)bind函数。

        (3)监听。

                a)将socket套接字由主动变为被动。

                b)创建未完成连接队列、已完成连接队列;未完成连接接经历3次握手才变成已完成连接。

                c)listen函数。

        (4)提取。

                a)从已完成连接队列提取连接,创建一个新的已连接socket套接字用于和客户端通信。

                b)accept函数。

        (5)读写数据。

        (6)关闭socket。

客户端:

        (1)创建流式socket套接字。

                a)socket函数。

        (2)连接服务器。

                a)指定服务器的IP协议(IPV4或IPV6)、port、IP地址。

                b)connect函数(该函数包含TCP的三次握手)。

        (3)读写数据。

        (4)关闭socket。


socket相关结构体和函数

(1)IPV4套接字结构体

#include<netinet/in.h>

struct sockaddr_in {
    sa_family_t    sin_family; /* 协议:AF_INET */
    in_port_t      sin_port;   /* 端口 */
    struct in_addr sin_addr;   /* IP地址 */
};

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

(2)IPV6套接字结构体

#include<netinet/in6.h>

struct sockaddr_in6 {
    sa_family_t     sin6_family;   /* AF_INET6 */
    in_port_t       sin6_port;     /* port number */
    uint32_t        sin6_flowinfo; /* IPv6 flow information */
    struct in6_addr sin6_addr;     /* IPv6 address */
    uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */
};

struct in6_addr {
    unsigned char   s6_addr[16];   /* IPv6 address */
};

(3)通用套接字结构体

为了接口通用,出现通用套接字结构体。

#include<sys/socket.h>

struct sockaddr {
    sa_family_t sa_family; /* AF_INET 或 AF_INET6 */
    char sa_data[14]; /* address data */
};

(4) socke函数:创建套接字

#include<sys/socket.h>

int socket(int domain, int type, int protocol);
/*
功能:
    创建套接字
参数:
    domain:
        AF_INET
        AF_INET6
        等等
    type:
        SOCK_STREAM:TCP流式套接字
        SOCK_DGRAM:UDP报式套接字
        SOCK_RAW:组包更多
        等等
    protocol:0,自动填充
返回值:
    成功:文件描述符
    失败:-1
*/

(5)connect函数:客户端连接服务器

#include<sys/socket.h>

int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
/*
功能:
    连接服务器
参数:
    sockfd:套接字文件描述符
    addr:IPV4套接字结构体地址 强转为通用套接字结构体
              包含目的主机的IP和port
    addrlen:IPV4套接字结构体大小
返回值:
    成功:0
    失败:-1,并设置errno
        EACCES:权限不足或被防火墙拒绝
        EADDRINUSE:本地地址已被其他套接字使用
        ECONNREFUSED:远程主机拒绝连接
        ETIMEDOUT:连接超时
*/

(6)bind函数:服务器端绑定自己固定的IP和port

#include<sys/socket.h>

int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
/*
功能:
    给套接字sockfd绑定固定的的IP地址和port
参数:
    sockfd:套接字文件描述符
    addr:IPV4套接字结构体地址
    addrlen:IPV4套接字结构体大小
返回值:
    成功:0
    失败:-1
*/

(7)listen函数:服务器端监听是否有连接请求

#include<sys/socket.h>

int listen(int sockfd, int backlog);
/*
功能:
    监听是否有客户端请求连接
参数:
    sockfd:套接字文件描述符
    backlog:已完成连接数量与未完成连接数量之和的最大值,一般写128
返回值:
    成功:0
    失败:-1
*/

(8)accept函数: 从已完成连接队列提取连接

#include<sys/socket.h>

int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
/*
功能:
    从已完成连接队列提取连接
参数:
    sockfd:套接字文件描述符
    addr:IPV4套接字结构体地址,以获取的客户端IP和port信息
    addrlen:存储IPV4套接字结构体大小的变量的地址。
返回值:
    成功:新连接socket的文件描述符
    失败:-1
*/

TCP客户端连接服务器示例:

#include<arpa/inet.h>
#include<stdio.h>
#include<sys/socket.h>
#include<unistd.h>

int main() {

    /* 1.创建socket */
    int sock_fd;
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);

    /* 2.连接服务器 */
    // IPV4套接字结构体
    struct sockaddr_in addr;
    // IPV4
    addr.sin_family = AF_INET;
    // 服务器的port,转为网络字节序
    addr.sin_port = htons(8888);
    // 服务器IP地址,转为网络字节序存入addr.sin_addr.s_addr
    inet_pton(AF_INET, "192.168.0.11", &addr.sin_addr.s_addr);
    // 连接
    connect(sock_fd, (struct sockaddr*)&addr, sizeof(addr));

    /* 3.读写数据 */
    char buf[1024] = "";
    while (1) {
        int n = read(STDIN_FILENO, buf, sizeof(buf));  // 从终端读入buf
        write(sock_fd, buf, n);
        n = read(sock_fd, buf, sizeof(buf));
        write(STDOUT_FILENO, buf, n);
    }

    /* 4.关闭 */
    close(sock_fd);

    return 0;
}

运行结果:


TCP服务器端示例:

#include<stdio.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>

int main(int argc, const char* argv[]) {

    /* 1.创建socket */
    int lfd = socket(AF_INET, SOCK_STREAM, 0);

    /* 2.绑定本机IP地址和port */
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8000);
    // INADDR_ANY为0,表示绑定通配地址,即本地所有IP地址
    // addr.sin_addr.s_addr = INADDR_ANY; 
    inet_pton(AF_INET, "192.168.124.128", &addr.sin_addr.s_addr);
    int ret = bind(lfd, (struct sockaddr*)&addr, sizeof(addr));
    if(ret < 0) {
        perror("bind");
        exit(0);
    }

    /* 3.监听 */
    listen(lfd, 128);

    /* 4.提取 */
    struct sockaddr_in cliaddr;
    socklen_t len = sizeof(cliaddr);
    int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &len);
    char ip[16] = "";
    printf("新连接到来!IP:%s, port:%d\n", 
                inet_ntop(AF_INET, &(cliaddr.sin_addr.s_addr), ip, 16), 
                ntohs(cliaddr.sin_port));

    /* 5.读写 */
    char buf[1024] = "";
    while (1) {
        bzero(buf, sizeof(buf));
        int n = read(STDIN_FILENO, buf, sizeof(buf));  // 从终端读入buf
        write(cfd, buf, n);
        n = read(cfd, buf, sizeof(buf));
        printf("%s", buf);
    }

    /* 6.关闭 */
    close(lfd);
    close(cfd);

    return 0;
}

运行结果:

注意:服务器进程被杀死,其占用的端口不会立即释放,再次连接会出现如下错误:

因为系统防止短时间内频繁开关相同的端口而将端口设置为TIME_WAIT状态(一般为2MSL,MSL一般为30s),因此TIME_WAIT大概持续60s;过了TIME_WAIT状态才可使用该端口。

若要立即使用该端口,可使用端口复用机制。


补充:

读写时,除了使用read、write函数,还可使用recv和send函数:

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

ssize_t recv(int sockfd, void* buf, size_t len, int flags);

ssize_t send(int sockfd, const void* buf, size_t len, int flags);

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

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

相关文章

NeurIPS 2022 | 正则化分子构象场

编译 | 于洲 今天我们介绍来自复旦大学的Lihao Wang以及其他来自字节跳动AI实验室与清华大学AI产业研究院的成员发布在NeurIPS 2022会议上的工作&#xff0c;该文章介绍了一种新方法——正则化分子构象场&#xff08;RMCF&#xff09;&#xff0c;用于从化学结构中预测最有利的…

为什么聊天机器人界面不是未来

​ 0-1之间有无限多种状态 比如&#xff1a;0 按时上下班&#xff0c;用固定时间长度获取价值1 创业&#xff0c;用非线性时间&#xff0c;获取真实价值0-1 之间有无限多种状态 shadow ChatBot目前的交互界面有非常多值得被改进的体验机会。最近看到一篇非常有启发性的文章&…

【JY】浅析基于性能的抗震分析方法——性能设计

【写在前文】 在阅读此文前&#xff0c;可先看下以下文章&#xff1a; 【JY】基于性能的抗震设计&#xff08;一&#xff09; 【JY】基于性能的抗震设计&#xff08;二&#xff09; 【JY|理念】结构概念设计之(设计理念进展) 【性能设计】 建筑结构通常使用弹性分析进行抗震设计…

ProbTransformer:应对RNA折叠等自然过程数据模糊的神秘力量

编译 | 于洲‍ 今天我们介绍来自德国弗赖堡大学计算机科学系的Jrg K.H. Franke, Frederic Runge以及Frank Hutter发表在NeurIPS 2022会议上的工作&#xff0c;该文章介绍了一种新颖的基于概率的神经网络架构ProbTransformer&#xff0c;它是Transformer生态系统的一种层级增强&…

wangzherongyao PMO

感谢【五一节】大家的相遇&#xff0c;总结下。 2023年05月02日&#xff0c;【第一组】组队开黑 我总结了下这天为什么打的那么好&#xff0c;首先赛季初段位在王者附近&#xff0c;大家心态重视程度也高&#xff0c;不轻敌&#xff0c;也不盲目&#xff0c;运营好兵线一步一步…

springboot2集成knife4j(swagger3)

springboot2集成knife4j&#xff08;swagger3&#xff09; springboot2集成knife4j&#xff08;swagger3&#xff09; 环境说明集成knife4j 第一步&#xff1a;引入依赖第二步&#xff1a;编写配置类第三步&#xff1a;放行相关资源 & 保证启动了knife4j第四步&#xff1a…

Lecture 14:Life-long Learning

目录 Catastrophic Forgetting 灾难性遗忘(Catastrophic Forgetting)的克服之道 Selective Synaptic Plasticity Additional Neural Resource Allocation Memory Reply 其他 Catastrophic Forgetting ——为什么今日的人工智慧无法成为天网&#xff1f;灾难性遗忘 Life…

将ssh发布密钥添加到服务器的ssh授权密钥中,但是为什么我仍然无法ssh登录到此服务器?

我已经将ssh发布密钥添加到服务器的ssh授权密钥中&#xff0c;但是为什么我仍然无法ssh登录到此服务器&#xff1f; 即使将ssh公钥添加到服务器的授权密钥中&#xff0c;您也可能无法通过SSH登录到服务器&#xff0c;这有几个原因: 1.服务器的authorized_keys文件的权限不正确…

DAY 56 MySQL数据库的索引

索引的概念 索引是一个排序的列表&#xff0c;在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址&#xff08;类似于c语言的链表通过指针指向数据记录的内存地址&#xff09;。 使用索引后可以不用扫描全表来定位某行的数据&#xff0c;而是先通过索引表找到该行…

专业的媒体邀约服务

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体邀约是什么&#xff1f;专业的媒体邀约服务包含哪些内容&#xff1f;怎么选择合适的媒体邀约服务机构&#xff1f; 今天胡老师就跟大家分享下这方面你的经验。 一&#xff0c;媒体邀约…

【Java入门合集】第四章继承(三)

【Java入门合集】第四章继承&#xff08;三&#xff09; 博主&#xff1a;命运之光专栏&#xff1a;JAVA入门 学习目标 1.掌握继承性的主要作用、实现、使用限制&#xff1b; 2.掌握this和super的含义及其用法&#xff1b; 3.掌握方法覆写的操作&#xff1b; 4.掌握final关键字…

【Spring MVC】Web程序开发

文章目录 1. 什么是Spring MVC&#xff1f;2. 如何创建Spring MVC项目&#xff1f;3. 简单示例演示4. 路由接口映射4.1 RequestMapping4.2 GetMapping和PostMapping 5. 获取参数5.1 获取单个参数5.2 获取多个参数5.3 获取对象5.4 RequestParam参数重命名5.5 ResquestBody接收JS…

告别PPT手残党!这6款AI神器,让你秒变PPT王者!

如果你是一个PPT手残党&#xff0c;每每制作PPT总是让你焦头烂额&#xff0c;那么你一定需要这篇幽默拉风的推广文案&#xff01; 我向你保证&#xff0c;这篇文案将帮助你发现6款AI自动生成PPT的神器&#xff0c;让你告别PPT手残党的身份&#xff0c;成为一名PPT王者。 无论…

GoogleOptions命令行参数解析工具

GoogleOptions命令行参数解析工具 GoogleOptions GoogleOptions GoogleOptions是来自 Bazel Project 的命令行参数解析器。将 com.google.devtools.common.options 包拆分为一个单独的 jar&#xff0c;用于通用实用程序。 环境搭建: 引入maven依赖 <dependency><gr…

如何在Windows 10上使用Kali Linux应用程序

Linux操作系统在一些企业中越来越受欢迎。有许多发行版&#xff0c;包括Mint、Ubuntu和Kali。Kali是最著名的Linux发行版之一&#xff0c;渗透测试人员通常使用它。Kali Linux配备了一系列免费的开源软件&#xff0c;成为渗透测试的理想选择。目前&#xff0c;安全专家和渗透测…

【Vue】学习笔记-CLI Todo-List案例

学习笔记-CLI Todo-List案例 Todo-List案例src/App.vuesrc/components/MyHeader.vuesrc/components/MyList.vuesrc/components/MyItem.vuesrc/components/MyFooter.vue Todo-List案例 组件化编码流程 拆分静态组件&#xff1a;组件要按照功能点拆分&#xff0c;命名不要与html…

VSCode 开发flutter 实现设备远程调试

目前只找到了安卓的调试方案&#x1f62c;。 安卓端&#xff1a; 1首先安装 ADB Commanads for VSCode扩展 并且必须确保ADB已经添加到系统环境变量中 如未添加请按照下面的方式添加&#xff0c;如添加请直接跳到下面。 2添加环境变量&#xff08;windows可参考&#xff0c…

【Java系列】深入解析Java多线程

序言 你只管努力&#xff0c;其他交给时间&#xff0c;时间会证明一切。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记一级重要蓝色&#xff1a;用来标记二级重要 希望这篇文章能让你不仅有一定的收获&#xf…

sqli-labs通关(十七)

第十七关 这一关跟前面的关卡都不一样&#xff0c;是全新的关卡&#xff0c;页面是一个密码重置页面&#xff0c;需要输入用户名&#xff0c;然后输入新的密码&#xff0c;就会把我们的旧密码替换掉。所以就会用到数据库的update更新数据&#xff0c;不再是前面的查询数据&…

327页16万字市智慧人社项目建设方案(word可编辑)

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除 第 1 章 项目建设总体框架设计 1.1 系统总体架构设计 市智慧人社项目从总体逻辑上可分为信息访问层、门户层、应用服务层、应用支撑层、数据资源层和基础设施层等六个层次&a…