文章标题

来源:互联网 发布:sql exists in 效率 编辑:程序博客网 时间:2024/06/10 19:50

linux socket c/c++ 聊天

client_chat.c

#include <stdio.h>#include <stdlib.h>#include <netdb.h>#include <sys/types.h>#include <sys/socket.h>#include <string.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <fcntl.h>#include <malloc.h>#define MAXDATASIZE 256 //#define SERVPORT 4444  //服务器监听端口号#define STDIN 0  //标准输入文件描述符int main(int argc,char *argv[]){    char addr[30];    int sockfd;    struct sockaddr_in serv_addr;//Internet套接字地址结构    char buf[MAXDATASIZE];     //用于处理输入的缓冲区    char name[MAXDATASIZE];    char send_str[MAXDATASIZE]; //最多发送的字符不能超过256    int recvbytes;    fd_set rfd_set,wfd_set,efd_set; //select()监视读、写、异常处理的文件描述符集合      struct timeval timeout; //本次select()的超时结束时间    int ret; //与server连接的结果    if(argc<2)    {        printf("请输入服务器IP\n");        fgets(addr,256,stdin);        argv[1] = (char *)malloc(sizeof(argv[1]));        strcpy(argv[1],addr);    }    if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)    {        perror("socker error!");        exit(1);    }    //填充sockaddr结构    bzero(&serv_addr,sizeof(struct sockaddr_in));    serv_addr.sin_family = AF_INET;    serv_addr.sin_port = htons(SERVPORT);    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);    if(connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr))==-1)    {        perror("connect error!");        exit(1);    }    printf("已成功连接到服务器 %s\n",inet_ntoa(serv_addr.sin_addr));    fcntl(sockfd,F_SETFD,O_NONBLOCK);//服务器设为非阻塞    printf("要聊天首先要输入你的名字:");    scanf("%s",name);    name[strlen(name)] = '\0';    printf("%s:",name);    fflush(stdout);    send(sockfd,name,strlen(name),0);//发送用户名到sockfd    while(1)    {        //将select()监视的读,写,异常文件描述符清除        FD_ZERO(&rfd_set);        FD_ZERO(&wfd_set);        FD_ZERO(&efd_set);        //将标准输入文件描述符加到select()监视的读文件描述符集合中        FD_SET(STDIN,&rfd_set);        //添加新建的描述符加到select()监视的文件描述符中        FD_SET(sockfd,&rfd_set);    //  FD_SET(sockfd,&wfd_set);        FD_SET(sockfd,&efd_set);        //设置select在被监视窗口等待的时间        timeout.tv_sec = 10; //秒        timeout.tv_usec = 0; //微妙        ret = select(sockfd+1,&rfd_set,&wfd_set,&efd_set,&timeout);        if(ret==0)            continue;        if(ret<0)        {            perror("select error!");            exit(-1);        }        //判断是否已将标准输入文件描述符加到select()监视的读的文件描述符集合中        if(FD_ISSET(STDIN,&rfd_set))        {            fgets(send_str,256,stdin);//读取键盘输入的内容            send_str[strlen(send_str)-1] = '\0';            if(strncmp("quit",send_str,4)==0)            {                close(sockfd);                exit(0);            }            send(sockfd,send_str,strlen(send_str),0);        }        //判断是否已将新建的描述符加到select()监视的读的文件描述符集合中        if(FD_ISSET(sockfd,&rfd_set))        {            recvbytes = recv(sockfd,buf,MAXDATASIZE,0);            if(recvbytes==0)            {                close(sockfd);                exit(0);            }            buf[recvbytes] = '\0';            printf("Server: %s\n",buf);            printf("%s: ",name);            fflush(stdout);        }        //异常        if(FD_ISSET(sockfd,&efd_set))        {            close(sockfd);            exit(0);        }    }    return 0;}

server_chat.c

#include <stdio.h>#include <stdlib.h>#include <netdb.h>#include <sys/types.h>#include <sys/socket.h>#include <string.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <fcntl.h>#define MAXDATASIZE 256 //#define SERVPORT 4444  //服务器监听端口号#define BACKLOG 10 //最大连接请求数#define STDIN 0  //标准输入文件描述符int main(void){    FILE *fp;    int sockfd,client_fd;    int sin_size;    struct sockaddr_in my_addr,remote_addr;//本机地址信息,客户机地址信息    char buf[256];     //用于聊天的缓冲区    char buff[256];         //用于输入用户名的缓冲区    char send_str[256]; //最多发送的字符不能超过256    int recvbytes;    fd_set rfd_set,wfd_set,efd_set; //select()监视读、写、异常处理的文件描述符集合      struct timeval timeout; //本次select()的超时结束时间    int ret; //与client连接的结果    if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)    {        perror("socker error!");        exit(1);    }    //填充sockaddr结构    bzero(&my_addr,sizeof(struct sockaddr_in));    my_addr.sin_family = AF_INET;    my_addr.sin_port = htons(SERVPORT);    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);    //解决服务器关掉,启动“Address already in use”的情况    int on=1;    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));    if(bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr))==-1)    {        perror("bind error!");        exit(1);    }       if(listen(sockfd,BACKLOG)==-1)    {        perror("listen error!");        exit(1);    }    sin_size = sizeof(struct sockaddr_in);    if((client_fd=accept(sockfd,(struct sockaddr*)&remote_addr,&sin_size))==-1)    {        perror("accept error!");        exit(1);    }    printf("收到一个连接来自: %s\n",inet_ntoa(remote_addr.sin_addr));    fcntl(client_fd,F_SETFD,O_NONBLOCK);//服务器设为非阻塞    recvbytes = recv(client_fd,buff,MAXDATASIZE,0);    buff[recvbytes] = '\0';    fflush(stdout);    if((fp=fopen("name.txt","a+"))==NULL)    {        printf("cannot open file,exit...\n");        return -1;    }    fprintf(fp,"%s\n",buff);//将用户名写入到name.txt中    while(1)    {        //将select()监视的读,写,异常文件描述符清除        FD_ZERO(&rfd_set);        FD_ZERO(&wfd_set);        FD_ZERO(&efd_set);        //将标准输入文件描述符加到select()监视的读文件描述符集合中        FD_SET(STDIN,&rfd_set);        //添加新建的描述符加到select()监视的文件描述符中        FD_SET(client_fd,&rfd_set);        FD_SET(client_fd,&wfd_set);        FD_SET(client_fd,&efd_set);        //设置select在被监视窗口等待的时间        timeout.tv_sec = 10; //秒        timeout.tv_usec = 0; //微妙        ret = select(client_fd+1,&rfd_set,&wfd_set,&efd_set,&timeout);        if(ret==0)            continue;        if(ret<0)        {            perror("select error!");            exit(-1);        }        //判断是否已将标准输入文件描述符加到select()监视的读的文件描述符集合中        if(FD_ISSET(STDIN,&rfd_set))        {            fgets(send_str,256,stdin);//读取键盘输入的内容            send_str[strlen(send_str)-1] = '\0';            if(strncmp("quit",send_str,4)==0)            {                close(client_fd);                close(sockfd);                exit(0);            }            send(client_fd,send_str,strlen(send_str),0);        }        //判断是否已将新建的描述符加到select()监视的读的文件描述符集合中        if(FD_ISSET(client_fd,&rfd_set))        {            recvbytes = recv(client_fd,buf,MAXDATASIZE,0);            if(recvbytes==0)            {                close(client_fd);                close(sockfd);                exit(0);            }            buf[recvbytes] = '\0';            printf("%s: %s\n",buff,buf);            printf("Server: ");            fflush(stdout);        }        //异常        if(FD_ISSET(client_fd,&efd_set))        {            close(client_fd);            exit(0);        }    }}

makefile

all: client serv.PHONY:all# make client:client : client_chat.o    gcc -o client client_chat.oclient_chat.o : client_chat.c    gcc -c client_chat.c# make serv:serv : server_chat.o    gcc -o serv server_chat.oserver_chat.o : server_chat.c    gcc -c server_chat.c# make clean:clean :    rm -rf *.o client    rm -rf *.o serv
原创粉丝点击