IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> TCP并发服务器(多线程) -> 正文阅读

[网络协议]TCP并发服务器(多线程)

服务器:

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

#define SERVPORT 5000

//线程与进程相比:不关listenfd,将connfd传下来
//线程对公共区域可以用,线程不存在继承问题,这里不是公共区域
//创建进程需要分配空间,对系统资源消耗比较大,线程用的进程的空间,节俭系统资源

void * client_chart(void * arg)
{
    int connfd,n;//
    char msg[1000];
    socklen_t clilen;
    struct sockaddr_in cliaddr;

    clilen = sizeof(cliaddr);

    connfd =*((int *)arg);//得到主线程传给我的与客户端连接的套接口

    for(;;)
    {
        int i;
        n = recvfrom(connfd,msg,1000,0,(struct sockaddr*)&cliaddr,&clilen);
        //n是实际接收的字节数
        //sendto(connfd,msg,n,0,(struct sockaddr*)&cliaddr,sizeof(cliaddr));

        if(0 == n)
        {
            printf("client offline!\n");
            pthread_exit(NULL);//线程结束
        }

        printf("-------------------\n");
        
        msg[n] = '\0';

        printf("received the following:\n");

        printf("%s\n",msg);//数组的表示方式

        printf("-------------------------\n");

        for(i = 0;i < n;i++)
        {
            msg[i] = toupper(msg[i]);
        }

        sendto(connfd,msg,n,0,(struct sockaddr*)&cliaddr,sizeof(cliaddr));
    }
    close(connfd);

    return NULL;
}

int main()//线程——TCP的并发服务器
{
    int listenfd,connfd,n;//套接口,返回的字节数
    struct sockaddr_in servaddr,cliaddr;//服务器、客户端的地址
    socklen_t clilen;//客户端地址的长度,类型独特
    char msg[1000];//发送消息的缓冲区
    pid_t pid;
    int ret;
    pthread_t tid;

    listenfd = socket(AF_INET,SOCK_STREAM,0);

    bzero(&servaddr,sizeof(servaddr));//缓冲区取服务器的地址,
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERVPORT);//同一个服务器,地址相同

    bind(listenfd,(struct sockdaddr *)&servaddr,sizeof(servaddr));
    //监听套接口 

    listen(listenfd,100);
    while(1)//连接每一个客户端
    {
        clilen = sizeof(cliaddr);//为后面的客户端地址服务的

        connfd = accept(listenfd,(struct socdaddr*)&cliaddr,&clilen);

        //全局变量,只有一个,容易被覆盖
        //但connfd连接套接口是在监听到一个客户端后,就需要生产一个新的套接口

        ret = pthread_create(&tid,NULL,(void *)client_chart,(void*)&connfd);
    /*#if 0
        if((pid = fork()) == 0)//子进程里完成了和客户端会话的所有任务
        {

            //close(listenfd);线程对公共区域可以用,线程不存在继承问题,这里不是公共区域
            //创建进程需要分配空间,对系统资源消耗比较大,线程用的进程的空间,节俭系统资源
            for(;;)//只要输入有效的字符串,就可以多次发送、接收
            {
                int i;
            }
            close(connfd);//关闭会话的连接套接口
            //_exit(0);
        }
    #endif*/
    }
    
    close(listenfd);

    return 0;
}

客户端:

#include <stdio.h>
#include <sys/socket.h>//超级口都需要
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>

#define SERVPORT 5000
//客户端写程序时,运行的进程拆成两个线程(网上读、网上写分离)
//只有一个进程时,scanf就要挂起
//输入信息和接收信息是并行的

int main(int argc,char ** argv)//获取别人的ip地址可以从命令行里输进去
{
    int sockfd,n;
    struct sockaddr_in servaddr,cliaddr;//结构体加&,才变成指针,变成后"&servaddr"代表结构体的首地址
    char sendline[1000];//发送缓冲区大小
    char recvline[1000];//你们跟指针有什么关系,你们需要吗?他们是有自己空间的,数组名代表数组的首地址

    if(argc != 2)//如果命令行里没有输入服务器的地址
    {
        printf("usage:server address!\n");
        exit(0);//不是出错,是正常退出,程序命令正确,输入不符合规范
        //输入了服务器的地址,客户端可以连接服务器
    }

    sockfd = socket(AF_INET,SOCK_STREAM,0);//创建客户端的套接口

    bzero(&servaddr,sizeof(servaddr));//配置服务器的地址
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERVPORT);
    servaddr.sin_addr.s_addr = inet_addr(argv[1]);
    //服务器连接客户端时可以连接到客户端的任意网卡上
    //客户机连接时要有具体的服务器某网卡的地址

    connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

    while(fgets(sendline,1000,stdin) != NULL)//stdin是标准输入模型
    //输入scanf,从stdin中获得的值放到sendline缓冲区中
    //只要有数据,不停地发送、接收信息
    {
        sendto(sockfd,sendline,strlen(sendline),0,
                      (struct sockaddr *)&servaddr,sizeof(servaddr));
        //实际发送的字节数,与第三个形参有关

        n = recvfrom(sockfd,recvline,1000,0,NULL,NULL);
        //第二个形参void*可以不是指针
        //实际接收的字节数,与第六个形参有关

        recvline[n] = '\0';

        fputs(recvline,stdout);//输出printf,从recvline缓冲区中显示到stdout中
    }
    close(sockfd);

    return 0;
}

终端:

?

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-08-23 17:02:36  更:2021-08-23 17:04:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:26:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码