Linux下后台服务器开发_基于多线程的一对一QQ聊天室

废话不多说直接上干货

1.目标
在实现回声服务器和客户端后 ,基于多线程设计一对一的聊天室 


2.功能
在本机上实现客户端与服务器的实时聊天测试 以达到练习强化socket通信/多线程技术的目的


3.测试
客户端主线程 与两个子线程 

服务器主线程 与两个子线程

能够相互收到信息 并且进行应答

 最后关闭socket
代码如下:


客户端:

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

#define BUF_SIZE 1024
#define SERVER_PORT 666
#define SERVER_IP "127.0.0.1"

char buf_send[BUF_SIZE]={0};
char buf_recv[BUF_SIZE]={0};

//发送线程功能函数
void * sendMsg(void * socket){
    int *client_sock = (int *)socket;
    while(1){
        scanf("%s",buf_send);//buf_send表示数组元素首地址 此时再往里边输入数据 会覆盖掉原数据
        send(*client_sock, buf_send, strlen(buf_send), 0);//因为第一个形参传过来的是个地址所以加*号才是int

        //退出发送
        if(!strncasecmp(buf_send, "quit", 4)){
            //该函数就是对比第一个字符串和第二个字符串 的前4个字符是否相等 相等返回零
          break;
        }
    }
    pthread_exit(NULL);
}

//接受线程功能函数
void * recvMsg(void * socket){
    int *client_sock = (int *)socket;
    while(1){
        bzero(buf_recv, BUF_SIZE);//先把buf清零
        if(recv(*client_sock, buf_recv, BUF_SIZE, 0)>0){
          printf("Msg from server: %s\n", buf_recv);
        }

        if(!strncasecmp(buf_send, "quit", 4)){
            //该函数就是对比第一个字符串和第二个字符串 的前4个字符是否相等 相等返回零
          break;
        }
    }

    pthread_exit(NULL);

}

//客户端首先创建一个socket
//绑定想要连接的服务器的IP和端口号  然后调用connect函数通过socket去连接服务器
int main()
{
    int sockfd;

    struct sockaddr_in servaddr;
    int n;

    sockfd=socket(AF_INET, SOCK_STREAM, 0);

    memset(&servaddr, '\0', sizeof(struct sockaddr_in));
    //此处需要标明服务器的IP和端口
    servaddr.sin_family=AF_INET;
    //将IP和端口号进行转化  转化为网络字节序  就是socket函数使用的IP和端口格式
    inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr);
    servaddr.sin_port = htons(SERVER_PORT);


    if((connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))>=0){
        printf("连接成功!\n");
    }

    if((recv(sockfd, buf_recv, BUF_SIZE, 0))>0){
        printf("message from server: %s\n", buf_recv);

    }

     //创建线程用于收发
    pthread_t send_tid, recv_tid;
    pthread_create(&send_tid, NULL, sendMsg, (void *)&sockfd);
    pthread_create(&recv_tid, NULL, recvMsg, (void *)&sockfd);

    //此函数表示 子线程 结束 才能执行 主线程中后边的函数(防止子线程被中断)
    pthread_join(send_tid, NULL);
    pthread_join(recv_tid, NULL);

    close(sockfd);

   return 0;
}




服务器:

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


#define SERVER_PORT 666
#define BUF_SIZE 1024

char buf_send[BUF_SIZE] = "connection succeeded";
char buf_recv[BUF_SIZE];

//发送线程功能函数
void * sendMsg(void * socket){
    int *client_sock = (int *)socket;
    while(1){
        scanf("%s",buf_send);//buf_send表示数组元素首地址 此时再往里边输入数据 会覆盖掉原数据
        send(*client_sock, buf_send, strlen(buf_send), 0);//因为第一个形参传过来的是个地址所以加*号才是int

        //退出发送
        if(!strncasecmp(buf_send, "quit", 4)){
            //该函数就是对比第一个字符串和第二个字符串 的前4个字符是否相等 相等返回零
          break;
        }
    }
    pthread_exit(NULL);
}

//接受线程功能函数
void * recvMsg(void * socket){
    int *client_sock = (int *)socket;
    while(1){
        bzero(buf_recv, BUF_SIZE);//先把buf清零
        if(recv(*client_sock, buf_recv, BUF_SIZE, 0)>0){
          printf("Msg from client: %s\n", buf_recv);
        }

        if(!strncasecmp(buf_send, "quit", 4)){
            //该函数就是对比第一个字符串和第二个字符串 的前4个字符是否相等 相等返回零
          break;
        }
    }

    pthread_exit(NULL);


}


int main()
{
    int sock;//信箱
    int i;
    struct sockaddr_in server_addr;

    sock = socket(AF_INET, SOCK_STREAM, 0);//创建信箱

    bzero(&server_addr,sizeof(server_addr));//清空标签

    server_addr.sin_family=AF_INET;//选择协议族
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);//监听本地所有IP
    server_addr.sin_port=htons(SERVER_PORT);//绑定端口号

    bind(sock,(struct sockaddr *)&server_addr,sizeof(server_addr));//绑定IP和端口


    listen(sock,128);//监听客户端
    printf("等待客户端的连接\n");


    struct sockaddr_in client;
    int client_sock, len;

    char client_ip[32];//用来存客户端IP和端口  打印
   // char buf[256];//用来接客户端的数据

    socklen_t client_addr_len;
    client_addr_len = sizeof(client);
    client_sock = accept(sock, (struct sockaddr*)&client, &client_addr_len);
    printf("client ip:%s\t port:%d\n",
           inet_ntop(AF_INET,&client.sin_addr.s_addr,client_ip,sizeof(client_ip)),
           ntohs(client.sin_port));

    send(client_sock, buf_send, strlen(buf_send), 0);//建立连接成功,给客户端发一条信息

    //创建线程用于收发
    pthread_t send_tid, recv_tid;
    pthread_create(&send_tid, NULL, sendMsg, (void *)&client_sock);
    pthread_create(&recv_tid, NULL, recvMsg, (void *)&client_sock);

    //此函数表示 子线程 结束 才能执行 主线程中后边的函数(防止子线程被中断)
    pthread_join(send_tid, NULL);
    pthread_join(recv_tid, NULL);

    close(client_sock);
    close(sock);


    printf("finshed!\n");
    return 0;

}

重点:编译的时候 一定要加 -lpthread  (多线程)

结果:

 

后边有时间会接着改进,调试多人聊天模式,

有兴趣的可以一起来讨论交流,

待续。。。 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值