吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2716|回复: 18
收起左侧

[C&C++ 转载] C/C++ linux下的多线程socket通信

  [复制链接]
蟹老板阿 发表于 2020-12-28 22:38
分为C语言版和C++版
C语言版为简单的单向socket通信
C++版本为socket的聊天室通信版本
使用到多线程,编译的时候加上参数 -lpthread
以下是代码

c语言版本
[C] 纯文本查看 复制代码
#include <iostream>
// 文件名:client.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string>
#define MAX 4096
int main()
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in ser_addr;
    char recvline[100],sendline[100];

    if (sockfd == -1)
    {
        std::cout << "create socket error" << std::endl;
        printf("error");
        return 0;
    }

    std::cout << "create successful" << std::endl;
    memset(&ser_addr,0,sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_port = htons(7788);
    ser_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    //inet_pton(AF_INET,"192.168.0.2",&ser_addr.sin_addr);

    std::cout << "create successful" << std::endl;
    int temp = connect(sockfd,(const struct sockaddr*)&ser_addr,sizeof(ser_addr));
    std::cout << "create successful" << std::endl;

    if(temp < 0)
    {
        std::cout << "connect error" << std::endl;
	return 0;
    }
    
    std::cout << "Msg you can send:" << std::endl;
    //std::cin >> sendline;
    
    while(1)
    {
        std::cin >> sendline;
        if(sendline[0] == 'q' && sendline[1] == '\0')
        {
            break;
        }
        if (send(sockfd,(const void*)&sendline,strlen((const char*)&sendline),0) < 0)
        {
        std::cout << "send message error" << std::endl;
        return 0; 
        }
        memset(&sendline,0,sizeof(sendline));


    }
    
//    if (send(sockfd,(const void*)&sendline,strlen((const char*)&sendline),0) < 0)
 //   {
//	std::cout << "send message error" << std::endl;
//	return 0;
//    }
    close(sockfd);
    return 0;
}



[C] 纯文本查看 复制代码
#include <iostream>
//文件名:service.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string>
#include <thread>

#define MAX 4096

int main()
{
    int listenfd,connfd;
    struct sockaddr_in ser_addr;
    char buff[MAX];
    int n;
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1)
    {
        std::cout << "create socket error" << std::endl;
		//printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }
    std::cout << "create successful" << std::endl;    
    memset(&ser_addr,0,sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//ser_addr.sin_addr.s_addr = inet_addr("192.168.0.1");
    ser_addr.sin_port = htons(7788);

    if(bind(listenfd, (struct sockaddr*)&ser_addr, sizeof(ser_addr)) == -1)
    {
	std::cout << "bind socket error" << std::endl;
	return 0;
    }

    if(listen(listenfd,10) == -1)
    {
	std::cout << "failed to listen the socket" << std::endl;
	return 0;
    }
    std::cout << "listen success" << std::endl;
    int socketlen = sizeof(struct sockaddr_in);
    struct sockaddr_in client_addr;
    
    if( (connfd = accept(listenfd,(struct sockaddr*)&client_addr,(socklen_t*)&socketlen)) == -1)   
    {
        std::cout << "accept socket error" << std::endl;
    }


    while(1)
    {
//	if( (connfd = accept(listenfd,(struct sockaddr*)&client_addr,(socklen_t*)&socketlen)) == -1)
//	{
//		std::cout << "accept socket error" << std::endl;
//		continue;
//	}
        
	n = recv(connfd,buff,MAX,0);
	
        if(n > 0)
        {
            buff[n] = '\0';
            std::cout << buff << std::endl;
        }
        
	//close(connfd);
	memset(&buff,0,sizeof(buff));
    }
    close(listenfd);
    return 0;
}




-----------------------分割线,以下为cpp的聊天室版本------------------------------------


[C++] 纯文本查看 复制代码
#include <iostream>
//文件名:C_client.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string>
#include <thread>
#define MAX 4096
using namespace std;
class Client
{
public:
    Client();
    ~Client();

    char* get_sendbuff();
    void created_socket();
    int connect_socket();
    int send_socket(int,char*);
    void close_socket();
    int get_sockfd();
    void recv_socket();
    struct msgData
    {
        int id;
        char msg[MAX];
    };
private:
    int sendfd;
    int socketfd;
    struct sockaddr_in ser_addr;
    char recvbuff[MAX];
    char sendbuff[MAX];
    int connfd;;        //定义connect句柄
    int recvnum;        //定义recv句柄
};

Client::Client()
{
    socketfd = socket(AF_INET, SOCK_STREAM, 0);
    memset((void*)&ser_addr,0,sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    ser_addr.sin_port = htons(7788);
    memset(sendbuff,0,sizeof(sendbuff));
}

Client::~Client()
{

}

void Client::created_socket()
{
    if(socketfd == -1)
    {
        std::cout << "create socket error! " << std::endl;
    }
    else
    {
        std::cout << "create socket success..." << std::endl;
    }
}

int Client::connect_socket()
{
    connfd = connect(socketfd,(const struct sockaddr*)&ser_addr,sizeof(ser_addr));
    if (connfd < 0)
    {
        std::cout << "connect socket error" << std::endl;
        return -1;
    }
    else
    {
        std::cout << "connfd is " << connfd << std::endl;
        std::cout << "connect socket success " << std::endl;
        return 0;
    }
}

int Client::send_socket(int sockfd,char* sendline)
{
    sendfd = send(sockfd,(const void*)sendline,strlen((const char*)sendline),0);
    if (sendfd < 0)
    {
        std::cout << "send message failed..." << std::endl;
        return -1;
    }
}

void Client::recv_socket()
{
    while(1)
    {
        recvnum = recv(socketfd,recvbuff,MAX,0);
        if (recvnum > 0)
        {
            recvbuff[recvnum] = '\0';
            std::cout << recvbuff << std::endl;
            memset(recvbuff,0,sizeof(recvbuff));
        }
    }
}

char* Client::get_sendbuff()
{
    return sendbuff;
}

void Client::close_socket()
{
    close(socketfd);
}

int Client::get_sockfd()
{
    return socketfd;
}

int main()
{
    cout << "enter your name please:";
    char name[10];
    cin >> name;
    
    char* psend;
    Client socking;
    psend = socking.get_sendbuff();
    socking.created_socket();
    if (socking.connect_socket() == -1)
    {
        return 0;
    }
    std::thread t1(&Client::recv_socket,&socking);
    while(1)
    {
        cin.getline(psend,200);
        if (psend[0] == 'q' && psend[1] == '\0')
        {
            break;
        }
        char s[MAX+20];
        sprintf(s,"%s%s%s",name,":",psend);
        if (socking.send_socket(socking.get_sockfd(),s) == -1)
        {
            std::cout << "send messages failed..." << std::endl;
            return 0;
        }
    }
    socking.close_socket();
    t1.detach();
}



[C++] 纯文本查看 复制代码
#include <iostream>


//文件名: C_service.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string>
#include <thread>
#include <mutex>
#include <pthread.h>
#include <vector>
#include <unistd.h>
#include <algorithm>
#include <map>
#include <set>
#define MAX 4096
using namespace std;
std::set<int> clientfd;     //全局的set容器clientfd,存放不同客户端的connfd(句柄)
std::mutex mtx;             //多线程的锁
class Service               //服务端类
{
public:
    Service();
    ~Service();
    void   created_socket();            //创建socket套接字
    void   bind_socket();               //绑定服务器端口用于监听和接收message
    void   listen_socket();             //监听端口
    void   accept_socket();             //接受客户端连接
    void   receive_socket();            //接收message
    void   close_socket();              //关闭套接字
private:
    int    socketfd;                    //定义套接字
    int    connfd;                      //定义一个accept的句柄,用于recv函数的参数
    struct sockaddr_in ser_addr;        //定义服务端地址的结构体
    char   recvbuff[MAX];               //接收的数据
    int    recvnum;                     //创建recv句柄
    struct sockaddr_in client_addr;     //定义客户端地址的结构体
    int    socketlen;                   //定义结构体长度(这个定义有点重复了)
    int    reuse;                       //定义端口重用
};


Service::Service()
{
    socketfd = socket(AF_INET, SOCK_STREAM, 0);                             //套接字
    memset((void*)&ser_addr,0,sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;                                          //定义服务端地址
    ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    ser_addr.sin_port = htons(7788);
    socketlen = sizeof(struct sockaddr_in);
    memset(recvbuff,0,sizeof(recvbuff));
    reuse = 1;
    setsockopt(socketfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));      //使端口可重用
}

Service::~Service()
{

}

void Service::created_socket()
{
    if(socketfd == -1)
    {
        std::cout << "create socket error! " << std::endl;
    }
    else
    {
        std::cout << "create socket success..." << std::endl;
    }
}

void Service::bind_socket()
{
    if(bind(socketfd, (struct sockaddr*)&ser_addr, sizeof(ser_addr)) == -1)
    {
        std::cout << "bind socket error" << std::endl;
    }
    else
    {
        std::cout << "bind socket success..." << std::endl;
    }
}

void Service::listen_socket()
{
    if(listen(socketfd,10) == -1)
    {
        std::cout << "failed to listen the socket" << std::endl;
    }
    else
    {
        std::cout << "listen socket success..." << std::endl;
    }
}

void Service::accept_socket()
{
    connfd = accept(socketfd,(struct sockaddr*)&client_addr,(socklen_t*)&socketlen);
    if(connfd == -1)
    {
        std::cout << "accept socket error" << std::endl;
    }
    else
    {
        std::cout << "connfd is " << connfd << std::endl;
        std::cout << "accept socekt success" << std::endl;
    }
    mtx.lock();                                            //多线程的锁,避免多线程同时操作变量
    clientfd.insert(connfd);
    mtx.unlock();
}

void Service::receive_socket()
{
    while(1)
    {
        recvnum = recv(connfd,recvbuff,MAX,0);
        if(recvnum > 0)
        {
            set<int> i = clientfd;
            recvbuff[recvnum] = '\0';
            std::cout << recvbuff << std::endl;
            if (i.size() > 0)
            {
                for (auto iter = i.begin();iter != i.end();++iter)
                {
                    if (*iter == connfd)
                    {
                        continue;
                    }
                    send(*iter,recvbuff,sizeof(recvbuff),0);
                }
            }
        }
        else if(recvnum == 0)
        {
            break;
        }
    }

}


void thread_listen(Service s)
{
    while(1)
    {
        s.listen_socket();
        s.accept_socket();
        s.receive_socket();
    }

}

int main()
{
    Service socking;
    socking.created_socket();
    socking.bind_socket();
    std::thread t1(thread_listen,socking);
    std::thread t2(thread_listen,socking);
    std::thread t3(thread_listen,socking);
    t1.join();
    t2.join();
    t3.join();
}

免费评分

参与人数 4吾爱币 +3 热心值 +4 收起 理由
tlf + 1 我很赞同!
seeyou_shj + 1 + 1 热心回复!
Lucifer_BW + 1 + 1 热心回复!
古月不傲 + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 蟹老板阿 发表于 2020-12-29 16:51
古月不傲 发表于 2020-12-29 00:27
辛苦了,建议成员函数都加上m_, 初始化列表成员该初始化初始化一下
尽量用namespace包裹起来,模块化好读
...

非常感谢,
但是namespace我考虑过,之所以没有加,因为工程太小,名称空间觉得加上去意义不大,基本上成员变量能在构造里写的我都写了,如有遗漏我会检查
后期我会学习您分享的代码,谢谢
古月不傲 发表于 2020-12-29 00:27
本帖最后由 古月不傲 于 2020-12-29 02:45 编辑

辛苦了,建议成员函数都加上m_, 初始化列表成员该初始化初始化一下
尽量用namespace包裹起来,模块化好读
可以参考下:链接: https://pan.baidu.com/s/17SEVyBiZSSZ0jSREmI9jow  密码: i90u
184697211 发表于 2020-12-29 00:10
cao777 发表于 2020-12-29 06:22
古月不傲 发表于 2020-12-29 00:27
辛苦了,建议成员函数都加上m_, 初始化列表成员该初始化初始化一下
尽量用namespace包裹起来,模块化好读
...

真 大佬!成员函数加上m_
BaconOle 发表于 2020-12-29 07:56
客户端一个socket监听,把接收到的socket放到容器里多线程里,可以用epoll模式监听。设置超时检测,一段时间不活跃的socket将他移出容器,减轻遍历压力
wsxzaq 发表于 2020-12-29 08:39
正在学习windows下的网络编程,正好可以参考一下
头像被屏蔽
tlf 发表于 2020-12-29 08:41
提示: 作者被禁止或删除 内容自动屏蔽
lyf9ljh 发表于 2020-12-29 09:00
学习了。学习了。
yjczawyl 发表于 2020-12-29 09:15
占座 流个痕迹!!
jkj 发表于 2020-12-29 09:17
是TCP的。socket的是标准的,和windows的基本相同 。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 14:31

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表