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

news2024/11/22 15:23:19

socket

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

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

socket必须成对出现。

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


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

客户端:

        (1)创建socket套接字。

                a)socket函数。

        (2)连接服务器。

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

                b)connect函数。

        (3)读写数据。

        (4)关闭socket。

服务器端:

        (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。


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

运行结果:

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

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

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

相关文章

[230507]托福听力真题TPO66词汇 |无重复|20:50~21:55 + 8:00~8:30

目录 conversation 1 conversation 2 ​ TPO66 Lecture ppt词汇 TPO66 Lecture 笔记词汇 conversation 1 conference / ˈkɑːnfərəns /n 会议terrific / təˈrɪfɪk /adj 极好的presentation / ˌpriːz(ə)nˈteɪʃ…

发送Ajax get请求详解

发送AJAX get请求&#xff0c;前端代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>ajax get请求</title> </head> <body> <script type"text/java…

第三十一章 Unity骨骼动画

关于骨骼动画的原理&#xff0c;我们这里不再详细介绍&#xff0c;有不清楚的可以回去看DirectX课程和3dsMAX课程。接下来&#xff0c;我们来讲解一下Unity的骨骼动画系统。Unity 的动画系统基于动画剪辑&#xff08;Animation Clip&#xff09;的概念&#xff0c;它的本质就是…

Linux 安装时,各个分区的作用是什么?

在这里&#xff0c;我说说一开始Linux为什么需要分区。 因为 Linux 是一个多用户操作系统。 多用户意味着一个问题&#xff1a;并非所有用户的操作都是可控的。 而系统正常运行的话&#xff0c;必须要一定的剩余空间。 这也就意味着&#xff1a;如果一个用户自己把空间占满…

MySQL数据库之用户管理

一、数据库用户管理 1.1 新建用户 CREATE USER 用户名来源地址 [IDENTIFIED BY [PASSWORD] 密码]; 即&#xff1a;create user 用户名源地址 identified by 密码; 用户名&#xff1a; 指定将创建的用户名 来源地址&#xff1a; 指定新创建的用户可在哪些主机上登录&…

线段树练习题(日程安排表、LC-307、LC-2407、LC-699)

线段树详解&#xff1a;https://leetcode.cn/problems/range-module/solution/by-lfool-eo50/ 文章目录 线段树线段树模板[729. 我的日程安排表 I](https://leetcode.cn/problems/my-calendar-i/)[731. 我的日程安排表 II](https://leetcode.cn/problems/my-calendar-ii/)[732.…

数据库基础及用户管理授权

数据库概念 关系型数据库 数据结构二维表格 库 -> 表 -> 列&#xff08;字段&#xff09;&#xff1a;用来描述对象的的一个属性&#xff1b;行&#xff1a;用来描述一个对象的信息 mysql&#xff08;5.7/8.0&#xff09; maridb ocracle postgresql sqlserver(windows…

2D火焰特效

Unity面片实现火焰效果 一、效果说明 大家好&#xff0c;我是阿赵。这是一个火焰的效&#xff0c;不过它不是粒子做的&#xff0c;是用一个面片做的&#xff0c;可以理解成是2D的特效。这个例子很简单&#xff0c;但可以拓展一下思路&#xff0c;原来除了用序列帧和粒子做动画…

将页面元素隐藏的10种方法

在Web开发中&#xff0c;隐藏页面元素使其视觉不可见是一个非常常见的需求。为了实现这一目标&#xff0c;我们通常会采用多种方法&#xff0c;最常用的例如CSS的display属性&#xff0c;只要设置为node即可隐藏元素。 本文将通过对当前所有可用的隐藏元素的方法做一个总结&…

Flink系列-11、Flink DataStream的Sink

版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。 大数据系列文章目录 官方网址&#xff1a;https://flink.apache.org/ 学习资料&#xff1a;https://flink-learning.org.cn/ 目录 Flink在批处…

云效/git 删除特殊字符远程分支

云效/git 删除特殊字符远程分支 一、查看所有分支二、删除分支三、验证 在使用云效时&#xff0c;不小心添加了一个错误分支 de’vdev &#xff0c;在云效手动删除时&#xff0c;报错“找不到分支”&#xff0c;无法删除。只能启动git命令进行查看&#xff0c;将步骤总结如下&a…

【JAVA】#详细介绍!!! 文件操作之文件内容操作(2)!

本文主要是针对文件内容的操作进行展开&#xff0c;文件内容操作无非就两种 1.针对文件进行“读” 2.针对文件进行“写” 目录 文件内容读写的形式 字符流 字节流 文件内容操作 InputStream&#xff1a;以字节流的形式进行读操作 创建方式&#xff1a; FileInputStream的…

2023年深圳CPDA数据分析师认证到这里就对了哦

CPDA数据分析师认证是大数据方面的认证&#xff0c;助力数据分析人员打下扎实的数据分析基础知识功底&#xff0c;为入门数据分析保驾护航。 帮助数据分析人员掌握系统化的数据分析思维和方法论&#xff0c;提升工作效率和决策能力&#xff0c;遇到问题能够举一反三&#xff0c…

MySQL索引的底层实现原理

索引的底层实现原理 数据库索引是存储在磁盘上的&#xff0c;当数据量大时&#xff0c;就不能把整个索引全部加载到内存了&#xff0c;只能逐一加载每一个磁盘块&#xff08;对应索引树的节点&#xff09;&#xff0c;索引树越低&#xff0c;越“矮胖”&#xff0c;磁盘IO次数…

主动式和被动式电容笔的区别在哪?苹果平替笔性价比高的

被动式电容笔与主动式电容笔最大的不同之处在于主动式电容笔具有更加广泛的应用领域&#xff0c;可以与各种种类的电容式屏幕相匹配。随着对电容笔的了解&#xff0c;电容笔的使用也日益广泛。而且平替电容笔的制造工艺已经日趋成熟&#xff0c;正在走向实用&#xff0c;并且已…

易观千帆 | Q1运营报告:手机银行MAU超5.3亿,行业“内卷”超出想象

易观&#xff1a;由中国电子银行网、易观分析联合发布的“2023中国手机银行综合运营报告”显示&#xff1a;在经济企稳回升的大背景下&#xff0c;中国手机银行第一季度综合运营指数季度内呈平稳上升态势&#xff0c;手机银行活跃人数环比增幅逐月递增&#xff0c;促使活跃用户…

Redis主从复制和哨兵模式

Redis主从复制 概念 主从复制&#xff0c;是指将一台Redis服务器的数据&#xff0c;复制到其他的Reds服务器。前者称为主节点(master / leader),后者称为从节点(slave / follower)。 数据的复制是单向的&#xff0c;只能由主节点到从节点。 Master以写为主&#xff0c;Slave…

无公网IP,SSH远程连接Linux CentOS服务器【内网穿透】

目录 视频教程 1. Linux CentOS安装cpolar 2. 创建TCP隧道 3. 随机地址公网远程连接 4. 固定TCP地址 5. 使用固定公网TCP地址SSH远程 本次教程我们来实现如何在外公网环境下&#xff0c;SSH远程连接家里/公司的Linux CentOS服务器&#xff0c;无需公网IP&#xff0c;也不…

Go语言的基础语法以及变量和常量

目录 基础语法 行分隔符 注释 标识符 变量 声明 赋值 作用域 常量 声明 iota 基础语法 行分隔符 在Go程序中&#xff0c;一般一行就是一个语句&#xff0c;不像Java等可以在一行写多个语句一样&#xff0c;而且最后也不需要用";"来结尾。 例如&#xf…

【华为OD机试 2023最新 】箱子之字形摆放(C语言题解 100%)

文章目录 题目描述输入描述输出描述备注用例题目解析C语言题目描述 有一批箱子(形式为字符串,设为str), 要求将这批箱子按从上到下以之字形的顺序摆放在宽度为 n 的空地,请输出箱子的摆放位置。 例如:箱子ABCDEFG,空地宽度为3,摆放结果如图: 则输出结果为: AFG BE C…