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

这篇具有很好参考价值的文章主要介绍了Linux网络编程:socket、客户端服务器端使用socket通信(TCP)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. socket概念

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

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

socket必须成对出现。

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


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

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

2.1 服务器端步骤:

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

2.2 客户端步骤:

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

                a)socket函数。

        (2)连接服务器。

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

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

        (3)读写数据。

        (4)关闭socket。


3. socket相关结构体和函数

3.1 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 */
};

3.2 socket相关函数

(1) 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
*/

(2)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:连接超时
*/

(3)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
*/

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

#include<sys/socket.h>

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

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

#include<sys/socket.h>

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

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

运行结果:

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


(2)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;
}

运行结果:

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

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

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

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

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


4. 补充:

4.1 recv和send

读写时,除了使用read、write函数,还可使用recv和send函数,用法类似于read和write,flags默认写0即可:

#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);

4.2 socket包裹函数

将socket编程常用函数中的错误判断等封装为函数,使用更方便: mayueming1/socket-wrap-func: socket常用的包裹函数 (github.com)文章来源地址https://www.toymoban.com/news/detail-500003.html

到了这里,关于Linux网络编程:socket、客户端服务器端使用socket通信(TCP)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Socket实例,实现多个客户端连接同一个服务端代码&TCP网络编程 ServerSocket和Socket实现多客户端聊天

    Java socket(套接字)通常也称作\\\"套接字\\\",用于描述ip地址和端口,是一个通信链的句柄。应用程序通常通过\\\"套接字\\\"向网络发出请求或者应答网络请求。 使用socket实现多个客户端和同一客户端通讯;首先客户端连接服务端发送一条消息,服务端接收到消息后进行处理,完成后再

    2024年02月12日
    浏览(46)
  • Socket网络编程(TCP/IP)实现服务器/客户端通信。

    一.前言 回顾之前进程间通信(无名管道,有名管道,消息队列,共享内存,信号,信号量),都是在同一主机由内核来完成的通信。 那不同主机间该怎么通信呢? 可以使用Socket编程来实现。 Socket编程可以通过网络来实现实现不同主机之间的通讯。 二.Socket编程的网络模型如

    2024年02月08日
    浏览(64)
  • python网络编程:通过socket实现TCP客户端和服务端

    目录 写在开头 socket服务端(基础) socket客户端(基础) 服务端实现(可连接多个客户端)  客户端实现 数据收发效果   近期可能会用python实现一些网络安全工具,涉及到许多关于网络的知识,逃不过的就是最基本的socket。本文将介绍如何通过python自带的socket库实现TCP客户

    2024年03月21日
    浏览(40)
  • 【Java网络编程】基于UDP-Socket 实现客户端、服务器通信

    ​ 哈喽,大家好~我是你们的老朋友: 保护小周ღ   本期为大家带来的是网络编程的 UDP Socket 套接字,基于 UDP协议的 Socket 实现客户端服务器通信 ,Socket 套接字可以理解为是,传输层给应用层提供的一组 API,如此程序,确定不来看看嘛~~ 本期收录于博主的专栏 : JavaEE_保

    2024年02月02日
    浏览(40)
  • 【Java】网络编程与Socket套接字、UDP编程和TCP编程实现客户端和服务端通信

    为什么需要网络编程? 现在网络普及程序越来越高,网络上保存着我们日常生活中需要的各种资源,使用程序通过网络来获取这些资源的过程就需要网络编程来实现。 什么是网络编程? 网络编程,指网络上的主机,通过不同的进程以程序的方式实现网络通信(网络数据传输)

    2024年02月17日
    浏览(48)
  • 网络编程-Socket通信实现服务器与客户端互传文件(JAVA语言实现)

    在网络通信协议下,实现网络互连的不同计算机上运行的程序间可以进行数据交换. 网络编程三要素:ip地址、端口、协议 ip地址: 每台计算机指定的一个标识符,127.0.0.1是回送地址,可以代表本机地址 ,一般用来测试使用 ipconfig:命令行中查看本机地址 ping ip地址:检查网络是

    2023年04月14日
    浏览(27)
  • 【Python】Python 网络编程 ( Socket 套接字简介 | Socket 套接字使用步骤 | Socket 套接字服务端与客户端开发 )

    Socket 套接字 是一种 进程之间的 通信机制 , 通过套接字可以在 不同的进程之间 进行数据交换 ; 在 网络编程 中 , Socket 套接字 主要用于 客户端 与 服务器 之间的 通信 , 大部分 网络相关的应用程序 , 都使用到了 Socket 套接字技术 ; 套接字有两种类型 : 流套接字 : 提供了一个可

    2024年02月15日
    浏览(41)
  • 网络编程3——TCP Socket实现的客户端服务器通信完整代码(详细注释帮你快速理解)

    本人是一个刚刚上路的IT新兵,菜鸟!分享一点自己的见解,如果有错误的地方欢迎各位大佬莅临指导,如果这篇文章可以帮助到你,劳请大家点赞转发支持一下! 今天分享的内容是TCP流套接字实现的客户端与服务器的通信,一定要理解 DatagramSocket,DatagramPacket 这两个类的作用以及方法

    2024年02月12日
    浏览(27)
  • Java【网络编程2】使用 TCP 的 Socket API 实现客户端服务器通信(保姆级教学, 附代码)

    📕各位读者好, 我是小陈, 这是我的个人主页 📗小陈还在持续努力学习编程, 努力通过博客输出所学知识 📘如果本篇对你有帮助, 烦请点赞关注支持一波, 感激不尽 📙 希望我的专栏能够帮助到你: JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统

    2024年02月05日
    浏览(41)
  • 【Linux | 网络编程】TCP的服务端(守护进程) + 客户端

    上一节,我们用了udp写了一个服务端和客户端之间通信的代码,只要函数了解认识到位,上手编写是很容易的。 本章我们开始编写tcp的服务端和客户端之前通信的代码,要认识一批新的接口,并将我们之前学习的系统知识加进来,做到融会贯通… 代码详情:👉 Gitee 对于TC

    2024年01月16日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包