Linux--tcp编程(循环读数据、多客户端)

这篇具有很好参考价值的文章主要介绍了Linux--tcp编程(循环读数据、多客户端)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、简介:

二、基础准备

1.IP地址转换函数:

2. 套接字地址结构

1.通用socket地址结构:

2.专用socket地址结构:

三、编程流程 

四、服务器端编程流程 

//头文件:

代码

 //可以查看端口号

五、客户端编程:

六、连接后运行结果

七、循环写入数据

1.客户端代码:

2.服务器端代码:

3.执行结果:

八、如果用两个终端同时运行./client会怎样?

1.结果如何:

2.数据还能发送吗?

3.中间数据去哪了?

4.总结:

九、利用多线程,同时运行多客户端

1.代码:

2.运行结果:


一、简介:

在linux操作系统下完成TCP(socket、bind、listen、accept、recv、close、send、connect)网络编程,TCP服务器利用socket通过网络收发数据的能力,使用bind指定ip+端口、listen创建监听队列、accept接受链接、recv接受发送的数据、send回复数据以及最后利用close关闭链接;TCP客户端首先创建socket,利用connect向服务器发起链接,send发送数据,recv接受服务器反馈回来的数据,最后close关闭链接。能够在服务端程序和客户端程序互相传递信息,并能够使用fork和thread完成多进程和多线程编程,使多个客户端能够同时向服务器端发送数据。

linux tcp程序,Linux命令,ui,网络,服务器

二、基础准备

1.IP地址转换函数:

linux tcp程序,Linux命令,ui,网络,服务器

 inet_addr :把字符串转换为整型 linux tcp程序,Linux命令,ui,网络,服务器

2. 套接字地址结构

通过socket可以在网络上进行数据的接收发送,(网络程序一定有套接字);

套接字包括IP地址和端口号

1.通用socket地址结构:

struct sockaddr
{
    sa_family_t sa_family;
    char sa_data[14];
};

2.专用socket地址结构:

//IPv4

struct sockaddr_in
{
    sa_family_t sin_family;//地址族

    u_int16 sin_port;//端口号

    struct om_addr sin_addr;//ip地址
};

//ipv6

struct in6_addr
{
    unsigned char sa_addr[16];//IPV6地址,要用网络字节序表示
};

 linux tcp程序,Linux命令,ui,网络,服务器

三、编程流程 

linux tcp程序,Linux命令,ui,网络,服务器

四、服务器端编程流程 

//头文件:

// man inet_addr

linux tcp程序,Linux命令,ui,网络,服务器

//服务器端两个套接字,一个是监听套接字,一个是连接套接字

//l链接n个客户端,就会产生n+1个描述符(多一个监听套接字)

//sockfd:监听套接字

//c:连接套接字

代码

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

int main()
{
    //1.创建套接字
    int sockfd=socket(AF_INET,SOCK_STREAM,0);//AF_INET是IPV4协议族
    if (sockfd==-1)
    {
        printf("创建套接字失败\n");
        exit(1);
    }//创建套接字失败了

    //2.设置IP端口
    struct sockaddr_in saddr,caddr;//服务器端、客户端
    memset(&saddr,0,sizeof(saddr));//把saddr全部置为0,即就是置空
    saddr.sin_family=AF_INET;//成员设置地址族
    saddr.sin_port=htons(6000);//主机转网络段整形,端口号,使用5000以上的端口,
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//回环地址,自己给自己发

    int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//绑定套接字,专用强转成通用套接字地址 //给套接字指定,使用saddr中给的IP地址和端口
    if(res==-1)//失败了,端口号(6000)被占用了;IP地址写错
    {
        printf("bind err\n");
        close(sockfd);//关闭套接字
        exit(1);//出错退出
    }

    //3.创建监听队列
    res=listen(sockfd,5);//5是循环复用的,不代表只能接受五个客户端消息
    if(res==-1)//失败了
    {
        close(sockfd);//如果忘记关闭,进程退出后也会自动关闭
        exit(1);
    }

    //4.客户端申请连接
    while(1)
    {
        int len=sizeof(caddr);//计算申请连接的客户端的套接字地址
        int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//可能会阻塞
        if(c==-1)//或者c<0
        {
            continue;//失败就继续接收
        }

        printf("accept client ip:%s,port=%d\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
        char buff[128]={0};

        //5.服务器端接收连接
        int n=recv(c,buff,127,0);//也可以用read,读取期望从c客户端的buff中读取127个字符
        //recv也可能会阻塞,客户端不发数据
        printf("recv:(%d):%s\n",n,buff);

        //6.服务器端回复
        send(c,"ok",2,0);//回复c客户端,2个字符的内容:“OK”,标志位为0

        //7.关闭连接
        close(c);//关闭


    }


}

 //可以查看端口号

linux tcp程序,Linux命令,ui,网络,服务器

五、客户端编程:

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

int main()
{
    int sockfd=socket(AF_INET,SOCK_STREAM,0);//TCP固定搭配
    if(sockfd==-1)//楚错了
    {   
        exit(1);
    }    

    //可以用bind(),绑定端口,但不这样,作为客户端,你只需要知道服务器的IP端口,发起连接,自己的IP端口系统分配即可;如果自己绑定,恰好用了已绑定的端口,反而用不成了,所以一般不指定

    struct sockaddr_in saddr;//服务器的IP端口
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(6000);//连接的服务器的端口号是6000
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    
    int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res==-1)//失败:服务器没运行;没网络;端口写错
    {   
        printf("connect failed\n");
        close(sockfd);
        exit(1);
    }   

    printf("input\n");
    char buff[128]={0};
    fgets(buff,128,stdin);

    send(sockfd,buff,strlen(buff)-1,0);
    memset(buff,0,128);
    recv(sockfd,buff,127,0);
    printf("buff=%s\n",buff);
    close(sockfd);

    exit(0);
    
}

六、连接后运行结果

linux tcp程序,Linux命令,ui,网络,服务器

七、循环写入数据

1.客户端代码:

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

int socket_init();
int main()
{
    int sockfd=socket_init();
    if(sockfd==-1)
    {   
        exit(0);
    }   
    while(1)
    {   
        struct sockaddr_in caddr;
        int len=sizeof(caddr);
        int c=accept(sockfd,(struct sockaddr*)&caddr,&len);

        if(c<0)
        {
            continue;
        }
        printf("accept c=%d\n",c);
        while(1)
        {
            char buff[128]={0};
            int n=recv(c,buff,127,0);
            if(n<=0)//出错,或者对方关闭
            {
                break;
            }
            // printf("recv %s\n",buff);
            printf("accept client ip:%s,port=%d rece:%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),buff);
            send(c,"OK",2,0);
        }
        close(c);
        printf("close\n");
    
    }   
    close(sockfd);
}

int socket_init()
{
    int sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(sockfd==-1)
    {   
        return -1; 
    }   

    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(6000);//网络字节 大端
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");

    int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res==-1)
    {   
        printf("bind err\n");
        return -1; 
    }   

    res=listen(sockfd,5);
    {   
        if(res==-1)
        {
            return -1; 
        }
        return sockfd;
    }   
}

2.服务器端代码:

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

int main()
{
    int sockfd=socket(AF_INET,SOCK_STREAM,0);
    if (sockfd==-1)
    {   
        printf("socket err\n");
        exit(0);
    }   

    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(6000);
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");

    int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res==-1)
    {   
        printf("connect failed\n");
        exit(0);
    }   
    while(1)
    {   
        printf("input:\n");
        char buff[128]={0};
        fgets(buff,128,stdin);
        if(strncmp(buff,"end",3)==0)
        {
            break;
        }
        send(sockfd,buff,strlen(buff)-1,0);
        memset(buff,0,128);
        int n=recv(sockfd,buff,127,0);
        if(n<=0)
        {
            printf("服务器关闭了");
            break;
        }
        printf("buff=%s\n",buff);

    }   
    close(sockfd);
}

3.执行结果:

linux tcp程序,Linux命令,ui,网络,服务器

八、如果用两个终端同时运行./client会怎样?

linux tcp程序,Linux命令,ui,网络,服务器

 

1.结果如何:

linux tcp程序,Linux命令,ui,网络,服务器

//第一个运行的终端发送成功,并且受到ok,但是第二个没有收到ok,服务器端也没有显示

2.数据还能发送吗?

//可以

linux tcp程序,Linux命令,ui,网络,服务器

 //无法通过end退出第二个终端

linux tcp程序,Linux命令,ui,网络,服务器

//但在第一个终端发送end,两个终端上的都推出了;

//收到两个123,证明两个终端的内容都收到了

//在第一个终端发送end,第二个收到了ok

//即就是:在第一个终端的连接断开后,第二个连接上了,最后双方收到数据和OK

3.中间数据去哪了?

 第二个终端发送的数据三次握手是已经建立好了的,但数据由于第一个终端达成了连接,第二个终端就在已完成三次握手的队列中,数据在服务器端的接收缓冲区;

//netstat -natp

linux tcp程序,Linux命令,ui,网络,服务器

// 50166端口的client有匹配的服务器端

//50172端口的client后面对应服务器是空的

//50172只有监听套接字,没有对应的服务端

//50172第二列的数字6,代表发了大小为6的内容,证明数据在服务器端的接收缓冲区

//圈起来的第一个./service第二列的1代表还有一个连接没处理(就是第二个终端运行的那个client)

4.总结:

如果可以循环发送,一个在发送,另一个会阻塞,直到第一个退出

九、利用多线程,同时运行多客户端

1.代码:

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

int socket_init();

void* fun(void* arg)
{
    int c=(int)arg;
    while(1)
    {   
        char buff[128]={0};
        int n=recv(c,buff,127,0);
        if(n<=0)
        {
            break;
        }
        printf("buff(%d)=%s\n",c,buff);
        send(c,"OK",2,0);
    }   
    close(c);
    printf("close\n");
}

int main()
{
    int sockfd=socket_init();
    if(sockfd==-1)
    {   
        exit(0);
    }   
    while(1)
    {   
        struct sockaddr_in caddr;
        int len=sizeof(caddr);
        int c=accept(sockfd,(struct sockaddr*)&caddr,&len);

        if(c<0)
        {
            continue;
        }
        printf("accept c=%d\n",c);
        pthread_t id; 
        pthread_create(&id,NULL,fun,(void*)c);
    }   
    close(sockfd);
}

int socket_init()
{
    int sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(sockfd==-1)
    {   
        return -1; 
    }   

    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(6000);//网络字节 大端
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");

    int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res==-1)
    {   
        printf("bind err\n");
        return -1; 
    }   

    res=listen(sockfd,5);
    {   
        if(res==-1)
        {
            return -1; 
        }
        return sockfd;
    }   
}
~   

2.运行结果:

linux tcp程序,Linux命令,ui,网络,服务器文章来源地址https://www.toymoban.com/news/detail-761141.html

到了这里,关于Linux--tcp编程(循环读数据、多客户端)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【Linux】TCP的服务端(守护进程) + 客户端

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

    2024年02月08日
    浏览(31)
  • ESP32网络编程-TCP客户端数据传输

    本文将详细介绍在Arduino开发环境中,实现一个ESP32 TCP客户端,从而达到与TCP服务器数据交换的目标。 Internet 协议(IP)是 Internet 的地址系统,具有将数据包从源设备传递到目标设备的核心功能。IP 是建立网络连接的主要方式,奠定了 Internet 的基础。IP 不负责数据包排序或错

    2024年02月03日
    浏览(30)
  • Linux 基于 TCP 协议的简单服务器-客户端应用

    目录 一、相关函数  1、listen() 2、accept() 3、connect()  4、两种IP地址转换方式  5、TCP和UDP数据发送和接收函数对比 5、log.hpp自定义记录日志 二、udp_server.hpp单进程版本 三、tcp_server.cc 四、Telnet客户端(代替tcp_client.cc) 五、多进程实现udp_server.hpp 1、多进程版本一 2、tcp_client.

    2024年04月27日
    浏览(37)
  • Linux下TCP网络服务器与客户端通信程序入门

    实现客户端连接服务器,通过终端窗口发送信息给服务器端,服务器接收到信息后对信息数据进行回传,客户端读取回传信息并返回。 服务器当前IP地址要知道 建立socket 绑定本地IP地址并设置端口号 知道服务器的IP地址和端口号 然后进行连接

    2024年02月14日
    浏览(48)
  • Linux网络编程:Socket服务器和客户端实现双方通信

    目录 一,什么是网络编程 二,为什么使用端口号 三,TCP协议与UDP协议 ①TCP(传输控制协议) ②UDP(用户数据报协议,User Data Protocol) ③总结归纳 四,Socket服务器和客户端的开发流程 五,服务器和客户端相关API说明 ①socket()函数 ②bind()函数 ③listen()函数 ④accept()函数 ⑤客户端

    2024年02月11日
    浏览(53)
  • 一台linux服务器最多能支持多少个TCP连接?(要区分客户端还是服务端)

    参考大佬文章: 一台机器最多能撑多少个TCP连接? 今天掰扯清楚! 这个问题要分场景,先说下结论: 客户端: 最多支持TCP连接数 = IP数 * 端口数 = IP数 * 65535 ,其中的IP数是由于linux下可以配置多IP 服务端:取决于linux服务器的内存大小, 内存数 / 静默TCP连接所占大小 3.3k ,

    2024年02月09日
    浏览(44)
  • Linux网络编程:Socket套接字编程(Server服务器 Client客户端)

    文章目录: 一:定义和流程分析 1.定义 2.流程分析  3.网络字节序 二:相关函数  IP地址转换函数inet_pton inet_ntop(本地字节序 网络字节序) socket函数(创建一个套接字) bind函数(给socket绑定一个服务器地址结构(IP+port)) listen函数(设置最大连接数或者说能同时进行三次握手的最

    2024年02月12日
    浏览(67)
  • Linux下网络编程(3)——socket编程实战,如何构建一个服务器和客户端连接

            经过前几篇的介绍,本文我们将进行编程实战,实现一个简单地服务器和客户端应用程序。 编写服务器程序          编写服务器应用程序的流程如下:         ①、调用 socket()函数打开套接字,得到套接字描述符;         ②、调用 bind()函数将套接字

    2024年02月03日
    浏览(47)
  • Linux系统编程,使用C语言实现简单的FTP(服务器/客户端)

    前言 跟着上官社长 陈哥花了一个月的时间终于把Linux系统编程学的差不多了,这一个月真的是头疼啊,各种bug,调的真心心累,不过好在问题都解决掉了,在此也感谢一下答疑老师,给我提供了很多的思路,本文章是对前段时间学习Linux,做一个小小的总结,才疏学浅,只学

    2024年02月12日
    浏览(51)
  • 使用IO多路复用select完成TCP循环服务器接收客户端消息并打印

    服务器       客户端     结果    

    2024年02月12日
    浏览(37)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包