网络编程QQ实现

Message.h

#ifndef _MESSAGE_H_
#define _MESSAGE_H_
#include<string.h>
#include<stdlib.h>
typedef struct loing
{
    int fid;
    char username[20];
    struct loing* next;
} loing;

loing * Init()
{
    loing* head =(loing*)malloc(sizeof(loing));
    head->next = NULL;
    return head;
}
int Selectname(loing* head, char* name)
{
    loing* p1 = head->next;
    int ret = 0;
    while(p1!=NULL)
    {
        if(strcmp(name,p1->username)==0)
        {
            ret = p1->fid;
            break;
        }
        p1=p1->next;
    }

    return ret;

}

int  Inset(loing* head,int id,char *name)
{
    int ret = 0;
    if((ret=Selectname(head,name))>0)
    {
        return ret;
    }
    else{
        loing *p2 = (loing*)malloc(sizeof(loing));
        p2->fid = id;
        strcpy(p2->username,name);
        p2->next = NULL;
        p2->next = head->next;
        head->next = p2;
        return ret;
    }
}
int Deletename(loing* head, char* name)
{
    loing* p1 = head->next;
    loing* p2 = head;
    int ret = 0;
    while(p1!=NULL)
    {
        if(strcmp(name,p1->username)==0)
        {
            ret =p1->fid;
            p2->next = p1->next;
            free(p1);
            break;
        }
        p2 = p2->next;
        p1=p1->next;
    }

    return ret;
}
typedef struct Mesg
{
    int id;
    char username[20];
    char destname[20];
    char message[1024];
}Mesg;
#endif


wrap.h
#ifndef __WRAP_H__
#define __WRAP_H__
void sys_err_exit(const char*s );
int Accept(int fd ,struct sockaddr *sa ,socklen_t *salenptr);
void Bind(int fd,const struct sockaddr *sa,socklen_t salen);
void Connect(int fd,const struct sockaddr *sa,socklen_t salen);
void Listen(int fd,int backlog);
int Socket(int family,int type,int protocol);
ssize_t Write(int fd,const void *ptr,size_t nbytes);
void Close(int fd);
ssize_t Read(int fd,void* ptr,size_t nbytes);
ssize_t Readn(int fd,void *vptr,size_t n);
ssize_t Writen(int fd,const void *ptr,size_t nbytes);
static ssize_t my_read(int fd,char *ptr);
ssize_t ReadLine(int fd,void* vptr,size_t maxlen);
#endif

wrap.c
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
#include<sys/socket.h>

void sys_err_exit(const char* str)
{
    perror(str);
    exit(1);
}
//对accept函数的从新封装
int Accept(int fd,struct sockaddr *sa,socklen_t *salenptr)
{
    int n;
again:
    if((n = accept(fd,sa,salenptr))<0)
    {
        if((errno == ECONNABORTED) || (errno == EINTR))
            //如果是网络重链接错误,或者时信号打断则从新接受链接
            goto again;
        else
            sys_err_exit("accept error");
    }
    return n;

}

//对bind函数的封装
void Bind(int fd, struct sockaddr* sa,socklen_t salen)
{
    if(bind(fd,sa,salen)<0)
        sys_err_exit("bind error");
}
//对connect函数的封装
void Connect(int fd,const struct sockaddr *sa,socklen_t salen)
{
    if(connect(fd,sa,salen) < 0)
        sys_err_exit("connect error");
}

//对listen函数的封装
void Listen(int fd,int backlog)
{
    if(listen(fd,backlog) < 0)
        sys_err_exit("listen error");
}

//对socket函数的封装

int Socket(int family,int type,int protocol)
{
    int n;
    if((n = socket(family,type,protocol)) < 0)
        sys_err_exit("socket error");
    return n;
}

//对read函数的封装

ssize_t Read(int fd,void *ptr,size_t nbytes)
{
    ssize_t n;
again:
    if((n = read(fd,ptr,nbytes)) == -1)
    {
        if(errno == EINTR)
            //如果时被信号打断从新去读
            goto again;
        else 
            return -1;
    }

    return n;

}

//对write函数的封装
ssize_t Write(int fd,const void *ptr,size_t nbytes)
{
    ssize_t n;
again:
    if((n=write(fd,ptr,nbytes))==-1)
    {
        if(errno == EINTR)
            goto again;
        else
            return -1;
    }

    return n;
}
//对close函数的封装
void Close(int fd)
{
    if(close(fd)==-1)
        sys_err_exit("close error");
}

//对读n个字节的封装
ssize_t Readn(int fd,void *vptr,size_t n)
{
    size_t nleft;//剩余的字节
    ssize_t nread; //已经读的字节
    char *ptr;

    ptr = vptr;
    nleft = n;
    while(nleft > 0)
    {
        if((nread = read(fd, ptr, nleft))<0)
        {
            if(errno == EINTR)
                //如果时被信号打断已经读的清除
                nread = 0;
        else 
            return -1;
        }
        else if(nread == 0)//另一端已经关闭
            break;

        nleft -= nread;//计算还剩余多少字节没有读
        ptr += nread;//指针后移到已经读的字节,以便下次从此处继续保存


    }
    return n-nleft;//返回实际读到的字节数
}

//对读n个字节的封装
ssize_t Writen(int fd,const void *vptr,size_t n)
{
    size_t nleft;
    ssize_t nwritten;
    const char *ptr;

    ptr = vptr;
    nleft = n;
    while(nleft > 0)
    {
        if((nwritten = write(fd,ptr,nleft)) < 0)
        {
            if(nwritten < 0 && errno == EINTR)
                nwritten = 0;
            else 
                return -1;
        }
        nleft -= nwritten;
        ptr += nwritten;
    }

    return n;
}


//预读取函数
static ssize_t my_read(int fd,char *ptr)
{
    static int read_cnt;
    static char *read_ptr;
    static char read_buf[100];

    if(read_cnt <= 0)
    {
again:
        if((read_cnt = read(fd,read_buf,sizeof(read_buf)))<0)
        {
            if(errno == EINTR)
                goto again;
        return -1;
    }
    else if(read_cnt == 0)
        return 0;
    read_ptr = read_buf;
    }

    read_cnt-- ;
    *ptr = *read_ptr++;
    return 1;


}

//读一行函数封装
ssize_t ReadLine(int fd,void *vptr,size_t maxlen)
{
    ssize_t n,rc;
    char c,*ptr;

    ptr = vptr;
    for(n=1;n < maxlen;n++)
    {
        if((rc = my_read(fd,&c)) ==1 )
        {
            *ptr++ = c;
        if(c == '\n')
            break;
        }
        else if(rc == 0)
        {
            *ptr = 0;
            return n-1;
        }
        else 
        {
            return -1;
        }
    }
    *ptr = 0;
    return n;
}

Serve.c
#include<signal.h>
#include<pthread.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<stdlib.h>
#include<Message.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"wrap.h"
#define SERVE_PORT 8000
struct s_info
{
    struct sockaddr_in cliaddr;
    int connfd;
};
loing* head=NULL;
void sys_err(char *str)
{
    perror(str);
    exit(1);
}
pthread_mutex_t conter_mutex = PTHREAD_MUTEX_INITIALIZER;
void dong(int i)
{



    while(waitpid(0,NULL,WNOHANG)>0)
        ;

}
void *do_work(void *arg)
{
    Mesg mes;
    struct s_info *ts = (struct s_info*)arg;
    int cilenfd = ts->connfd;
    char str[INET_ADDRSTRLEN];
    printf("Mssage from IP %s at PORT %d \n ",inet_ntop(AF_INET,&(*ts).cliaddr.sin_addr,str,sizeof(str)),ntohs((*ts).cliaddr.sin_port));
    pthread_detach(pthread_self());
    while(1)
    {
        int n = 0;
        //从公共管道中读取数据
        n = read(cilenfd,&mes,sizeof(mes));

        if(n>0)
        {     //如果id是1则代表登录
            if(mes.id == 1)
            {

        //      if(head == NULL)
        //          printf("head is NULL\n");
                //登录时打开私有管道,并把pid写如链表
            //  pthread_mutex_lock(&conter_mutex);
                int cilenfd1= Inset(head,cilenfd,mes.username);
            //  pthread_mutex_unlock(&conter_mutex);

        //      printf("%s,%d,%d\n",mes.username,cilenfd1,cilenfd);
                if(cilenfd1>0)//此处说明此用户已经登录过
                {
                    strcpy(mes.username,mes.username);
                    char mms[]="请不要重复登录";
                    strcpy(mes.message,mms);
                    mes.id=-1;
                    write(cilenfd1,&mes,sizeof(mes));


                }
                else
                {
                    strcpy(mes.username,mes.username);
                    char bbf[]="登录成功";
                    strcpy(mes.message,bbf);
                    write(cilenfd,&mes,sizeof(mes));

                }
            }
            if(mes.id == 2)
            {
                if(strcmp(mes.username,mes.destname)==0)
                    continue;
                int cilenfd1 = Selectname(head,mes.destname);
            //  printf("%s , %d\n",mes.destname,cilenfd1);
                if(cilenfd1 == 0)
                {
                    cilenfd1 = Selectname(head,mes.username);
                    char mms[50];
                    strcpy(mms,mes.destname);
                    char mm[] = " :没有在线,请稍等片刻";
                    strcat(mms,mm);
                    strcpy(mes.username,mes.username);
                    strcpy(mes.message,mms);
                    write(cilenfd1,&mes,sizeof(mes));

                }
                else
                    write(cilenfd1,&mes,sizeof(mes));

            }
            if(mes.id == 0)
            {
                int cilenfd1 = Deletename(head,mes.username);
                char tui[] ="退出成功!";
                strcpy(mes.username,mes.username);
                strcpy(mes.message,tui);
                mes.id = -1;
                write(cilenfd1,&mes,sizeof(mes));
            }
        }
    }
    Close(ts->connfd);
//  return (void*)0;

}

int main(void)
{
    head = Init();
    int servefd,cilenfd;
    char buf[1024];
    struct sockaddr_in serve,clien;
    char str[INET_ADDRSTRLEN];
    socklen_t cilen_len;
    //signal(SIGPIPE,dong);
    struct s_info ts[300];
    int t = 0;
    pthread_t tid;
    servefd = Socket(AF_INET,SOCK_STREAM,0);
    bzero(&serve,sizeof(serve));
    serve.sin_family = AF_INET;
    serve.sin_port = htons(SERVE_PORT);
    serve.sin_addr.s_addr = htonl(INADDR_ANY);

    int pot = 1;
    setsockopt(servefd,SOL_SOCKET,SO_REUSEADDR,&pot,sizeof(pot));
    Bind(servefd,(struct sockaddr*)&serve,sizeof(serve));

    Listen(servefd,20);
    printf("Accepting connections .....\n");

    while(1)
    {
        cilen_len = sizeof(clien);
        cilenfd = Accept(servefd,(struct sockaddr*)&clien,&cilen_len);
        ts[t].cliaddr = clien;
        ts[t].connfd = cilenfd;
        if(t>=300)
        {
            printf("cilen is too much\n");
            return 0;
        }
        pthread_create(&tid,NULL,do_work,(void*)&ts[t]);
        t++;
//      printf("t=%d\n",t);
    }
    return 0;
}


Clent.c
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<stdlib.h>
#include<Message.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<netinet/in.h>
#include"wrap.h"
#define SERVE_PORT 8000
#define SERVE_IP "192.168.42.27"
#define SERVE_FIFO "serve_public"
void sys_err(char *str)
{
    perror(str);
    exit(1);
}
int main(int argc,char* argv[])
{
    int plic_id,pive_id,read_id;
    struct sockaddr_in servaddr;
    int sockfd;

    int fbg;
    char buf[1024];
    Mesg loin,mes;
    if(argc<2)//判断输入格式是否正确
    {
        printf("%s\n","please input like:./clent username");
        return 0;
    }

    /*  //打包登录数据包
        loin.id=1;
        strcpy(loin.username,argv[1]);
     */ 
    sockfd = Socket(AF_INET,SOCK_STREAM,0);

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERVE_PORT);
    inet_pton(AF_INET,SERVE_IP,&servaddr.sin_addr.s_addr);
    Connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
    int flags;
    flags = fcntl(STDIN_FILENO,F_GETFL);
    flags |=O_NONBLOCK;
    if(fcntl(STDIN_FILENO,F_SETFL,flags) == -1)
            sys_err("fcntl stdin error");
    int flags1;
    flags1 = fcntl(sockfd,F_GETFL);
    flags1 |=O_NONBLOCK;
    if(fcntl(sockfd,F_SETFL,flags) == -1)
            sys_err("fcntl stdin error");
    //从公共管道传送到服务器,进行登录
    //   write(sockfd,&loin,sizeof(loin));
    char tui[]="T~";
    char de[]="D~";
    while(1)
    {
        strcpy(mes.username,argv[1]);
        int n =0;
        n = read(STDIN_FILENO,buf,1024);
        if(n > 0)
        {
            mes.id = 2;
            buf[n]='\0';
            strcpy(mes.destname,strtok(buf," "));
            strcpy(mes.message,strtok(NULL," "));
            if((strncmp(mes.message,tui,2)==0)) 
                mes.id = 0;
            if((strncmp(mes.message,de,2)==0))  
                mes.id = 1;
            write(sockfd,&mes,sizeof(mes));

        }
        int n1 =0;
        n1 = read(sockfd,&mes,sizeof(mes));
        if(n1>0)
        {
            printf("%s",mes.username);
            printf(":\n");
            printf("%s\n",mes.message);
            fflush(stdout);
            if(mes.id==-1)
            {
                exit(1);
            }
        }

    }
    return 0;
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
网络编程qq聊天系统是一种基于C语言和C编程知识以及少量算法和数据结构的项目。它主要利用UDP、TCP和P2P编程技术来实现。通过这个系统,用户可以在网络上进行实时的聊天和通信。这个系统可以分为两种类型,单纯型P2P和混合型P2P,而QQ则属于混合型P2P的应用。混合型P2P系统将传统的客户端-服务器模式与P2P的直接连接相结合,可以实现更高效的通信和更多的功能。网络编程qq聊天系统需要一定的编程基础,所以对于完全零基础的小伙伴来说可能不太适合下载学习。但对于有一定编程基础的人来说,学习网络编程qq聊天系统可以帮助他们更好地理解网络编程和P2P技术的工作原理。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [C/C++经典项目开发:腾讯QQ网络聊天系统](https://download.csdn.net/download/c_q_741818652/11109980)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [详解C# 网络编程系列:实现类似QQ的即时通信程序](https://download.csdn.net/download/weixin_38714641/14913919)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值