简易QQ聊天室,socket多线程编程(C语言实现),简单易懂

简易QQ聊天室

实现本功能,仅需了解socket套接字的使用,我已经将socket套接字的监听接受状态封装在了common.c中,相信你看了会有所收获,socket的连接也封装在common.c中。

我们要实现随时接收信息和发送信息两个功能,互不干扰,则需要创建一个线程仅仅接收信息,主进程仅仅发送信息(当然你也可以反过来)。
线程创建很简单。
函数声明:

int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict_attr,void*(*start_rtn)(void*),void *restrict arg);

参数
第一个参数为指向线程标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的地址。
最后一个参数是运行函数的参数。

具体使用: 最简单的,线程属性NULL,func函数参数为NULL

pthread_t t //线程id
pthread_create(&t, NULL, func, NULL);//void *func()函数里面的内容是这个线程的具体工作,下面实例中我会用到。
common.c
int connect_socket (int port, char *host) {
    int sockfd;
    struct sockaddr_in dest_addr;
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        //perror("socket() error\n");
        return -1;
    }
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(port);
    dest_addr.sin_addr.s_addr = inet_addr(host);
    if (connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(dest_addr))) {
        perror("connect() error");
        return -1;
    }
    return sockfd;
}

int bind_socket (int port) {
    int sockfd;
    struct sockaddr_in sock_addr;
    struct linger m_sLinger;
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket() error!\n");
        return -1;
    }
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_port = htons(port);
    sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (const char *)&m_sLinger, sizeof(struct linger));
    if ((bind(sockfd, (struct sockaddr *)&sock_addr, sizeof(struct sockaddr))) < 0) {
        close(sockfd);
        perror("bind() error!\n");
        return -1;
    }
    if (listen(sockfd, 20) < 0) {
        close(sockfd);
        perror("listen() error!\n");
        return -1;
    }
    printf("listening...\n");
    return sockfd;
}
server端
#include <stdio.h>
#include "head.h"
#include "common.c"

#define MAX_N 1024

void *send_func () {
    int sockfd, socket_listen, port;
    port = 6789;
    socket_listen = bind_socket(port);
    while (1) {
        struct sockaddr_in destaddr;
        socklen_t len;
        if ((sockfd = accept(socket_listen, (struct sockaddr *)&destaddr, &len)) < 0) {
            perror("accept error");
            exit(0);
        }
        //printf("connect\n");
        char str[MAX_N];
        int a;
        memset(str, 0, sizeof(str));
        while ((a = recv(sockfd, str, MAX_N, 0)) > 0) {
            printf("%s", str);
            memset(str, 0, sizeof(str));
        }
        close(sockfd);
    }
}

int main() {
    pthread_t send_t;
    if (pthread_create(&send_t, NULL, send_func, NULL)) {
        perror("pthread_create error");
        exit(0);
    }

    int sockfd, socket_listen, port;
    port = 8899;
    socket_listen = bind_socket(port);
    while (1) {
        struct sockaddr_in destaddr;
        socklen_t len;
        if ((sockfd = accept(socket_listen, (struct sockaddr *)&destaddr, &len)) < 0) {
            perror("accept error");
            exit(0);
        }
        //printf("connect\n");
        char str[MAX_N];
        while (1) {
            scanf("%[^\n]s", str);
            if (strlen(str) == 0 || strcmp(str, "byebye") == 0) {
                if (strlen(str)) send(sockfd, str, strlen(str), 0);
                getchar();
                break;
            }
            getchar();
            strcat(str, "\n");
            send(sockfd, str, strlen(str), 0);
            memset(str, 0, sizeof(str));
        }
        close(sockfd);
    }
    pthread_join(send_t, NULL);
    return 0;
}
client端
#include <stdio.h>
#include "head.h"
#include "common.c"

#define PATH_N 50
#define MAX_N 1024

void *send_func () {
    int sockfd;
    char host[PATH_N];
    strcpy(host, "127.0.0.1") //127.0.0.1是连接本机的ip地址,用ifconfig可以查看主机ip地址,填正确的ip就能连接。
    int port = 6789 //对应server端端口
    while (1) {
        sockfd = connect_socket(port, host); //主动去连接需要知道对方ip和端口
        if (sockfd < 0) {
            printf("sockfd < 0\n");
            close(sockfd);
            continue;
        }
        char buffer[MAX_N];
        int a;
        while(1){
            scanf("%[^\n]s", buffer);
            if (strlen(buffer) == 0 || strcmp(buffer, "bye") == 0) {
                if (strlen(buffer) == 0) {
                    getchar();
                    break;
                }
                close(sockfd);
                return NULL;
            }
            getchar();
            strcat(buffer, "\n");
            send(sockfd, buffer, strlen(buffer), 0);
            memset(buffer, 0, sizeof(buffer));
        }
        close(sockfd);
    }
    return NULL;
}

int main() {
    pthread_t recv_t;
    if (pthread_create(&recv_t, NULL, recv_func, NULL)) {
        perror("pthread_create error");
        exit(0);
    }
    
    int sockfd;
    char host[PATH_N];
   strcpy(host, "127.0.0.1") //127.0.0.1是连接本机的ip地址,用ifconfig可以查看主机ip地址,填正确的ip就能连接。
    int port = 8899//对应server端端口
    while (1) {
        sockfd = connect_socket(port, host);
        if (sockfd < 0) {
            printf("sockfd < 0\n");
            close(sockfd);
            continue;
        }
        char buffer[MAX_N];
        int a;
        while ((a = recv(sockfd, buffer, MAX_N, 0)) > 0) {
            if (strcmp(buffer, "byebye") == 0) {
                printf("%s\n", buffer);
                close(sockfd);
                return 0;
            }
            printf("%s", buffer);
            memset(buffer, 0, sizeof(buffer));
        }
        close(sockfd);
    }

    pthread_join(recv_t, NULL);
    return 0;
}
socket可能使用的头文件head.h
#include <arpa/inet.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <stdarg.h>
#include <pthread.h>
  • 2
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值