现在的位置: 首页 > 综合 > 正文

基于linux用C语言编写的局域网通信软件(在ubuntu上正常运行)

2013年12月03日 ⁄ 综合 ⁄ 共 14267字 ⁄ 字号 评论关闭

/************************************************************

去年学C语言socket通信时花三天时间写的。

功能

  A,私聊 B,群聊,C,从服务器下载文件 D,上传文件到服务器,E,用户上下线通知,F,刷新在线用户列表,E,下线

 

1,一般情况请使用SUDO
权限运行

2,服务器文件中心路径为 /home/file_centre
,若没有该文件夹,请创建

3,客户端下载到的文件保存路径为 /home/file_download
使用该功能前,请先创建该文件夹

4,请在linux环境下测试运行(我使用的是ubuntu

*****************************************************************/

//程序测试截图

 

 

说明:一共是三个文件:头文件,服务器代码,客户端代码。

/*头文件*/

#include<stdio.h>

#include<sys/types.h>          /* See NOTES */

#include<sys/socket.h>

#include<string.h>

#include<strings.h>

#include<stdlib.h>

#include<netdb.h>

#include<errno.h>

#include<string.h>

#include<pthread.h>

#include<unistd.h>

#include<signal.h>

#include<netinet/in.h>

#include<arpa/inet.h>

#include<fcntl.h>

#include<dirent.h>

#define MAXSIZE 512

 

/*服务器接收消息后,创建的在线用户列表*/

struct user_info{

       char user_name[20];

       int  id;

       struct sockaddr_in cli_addr;

       struct user_info *next;

};

/*客户端给服务器发送的消息*/

struct msg {

       char type;

       char self_name[20];

       char dst_name[20];

       char data[MAXSIZE];

};

/*消息类型定义*/

enum msg_type{           

       LOG_IN = 1,     //登录

       REFRESH,         //要求刷新用户在线用户(重新打印在线用户)

       CHAT_PRI,        //私聊消息

       CHAT_ALL,        //群聊消息

       DOWNLOAD,        //从服务器下载文件(下载之前先打印文件列表)

       UPLOAD,         //上传文件到服务器

       OFFLINE,      //下线通知

       OVER,            //服务器发送本次消息结束

       ERROR,           //重复登录

       FILE_NAME,       //发送文件列表

       FILE_ERROR //选择文件名失败

};

/*服务器总列表*/

struct servmsg

{

       struct msg recvmsg;

       struct sockaddr_in addr;

       struct servmsg *next;

};

 

/*客户端源程序  --liaoye928*/

#include"include.h"

 

static int cli_fd = -1; //主要套接字,用于接受服务器各种消息

static int sock_fd = -1; //组播套接字,用于群聊

static struct sockaddr_in serv_addr; //用于存储服务器IP和端口

static char myname[20]; //用于存储用户名

static pthread_t tid4 = -1; //将其定义为全局变量的原因是,接收线程会将其取消

/*创建数据报套接字函数*/

int udp_link(void)

{

      int sock_fd;

       sock_fd = socket(AF_INET,SOCK_DGRAM,0);

       return sock_fd;     

}

 

/*用于给服务其发送数据的函数*/

void send_sig(char myname[],char desname[],char data[],struct sockaddr_in serv_addr,char ch)

{

       struct msg mymsg;

       mymsg.type = ch;

       if(myname != NULL)

              strcpy(mymsg.self_name,myname);

 

       if(desname != NULL)

              strcpy(mymsg.dst_name, desname);

       if(data != NULL)

              strcpy(mymsg.data, data);

 

       if(sendto(cli_fd,&mymsg,sizeof(struct msg),0,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0){

                     perror("sendto");

                     exit(1);

       }

}

 

/*打印主菜单*/

void show_opt(void)

{

       printf("A@私聊模式》\tB@群聊模式》\nC@上传文件》\tD@下载文件》\nE@刷新列表》\tF@下线离开》\n");

       printf("请选择(如:A):\n");

}

/*接收消息函数,接收各种由服务器发来的数据,根据数据类型分别处理*/

void *recv_chat_func()

{

       int ret = -1;

       int i = 0;

       struct msg rcv_buf;

//     char quick_repeat[] = "亲,我有点事离开,稍后联系!";

       while(1){

              bzero(&rcv_buf,sizeof(rcv_buf));

              ret = recvfrom(cli_fd,&rcv_buf,sizeof(rcv_buf),0,NULL,NULL);

              if(ret < 0){

                     perror("recvfrom");

                     exit(1);

              }

//            printf("接收到消息,消息类型:%d\n内容:%s\n",rcv_buf.type,rcv_buf.data);

              rcv_buf.data[ret - sizeof(rcv_buf.type)-sizeof(rcv_buf.self_name)-sizeof(rcv_buf.dst_name)] = '\0';

              /*登录消息,刷新消息*/

              if(rcv_buf.type == LOG_IN || rcv_buf.type == REFRESH){

                     printf("@%s\t",rcv_buf.data);

                     fflush(NULL);

              }

              /*发送结束消息*/

              else if(rcv_buf.type == OVER){

                     printf("\n");

              }

              /*用户名重复提示消息*/

              else if(rcv_buf.type == ERROR){

                     printf("登录失败!\n");

                     printf("%s",rcv_buf.data);

                     exit(1);

              }

              /*下载时文件不存在提示消息*/

              else if(rcv_buf.type == FILE_ERROR){

                     printf("<文件传输>提示信息:%s\n",rcv_buf.data);

                     pthread_cancel(tid4); //如若输入文件名出错,取消线程,退出监听

              }

              /*文件名列表消息*/           

              else if(rcv_buf.type == FILE_NAME){

                     printf("<%s>\t\t",rcv_buf.data);

                     i++;

                     if(i%4 == 0){

                            printf("\n");

                     }

                     fflush(NULL);

                     }

              /*正常聊天消息(私聊)*/

              else {     

                     printf("新消息!===消息来自《%s:\n",rcv_buf.self_name);

                     printf("--------------------------\n");

                     printf("消息内容:%s",rcv_buf.data);

                     printf("(若要与%s聊天,请退回主界面重新选择私聊对象。)\n\n",rcv_buf.self_name);

              }

       }

}

 

/*私聊函数,参数均为全局变量*/

void chat_private(void)

{

       char peer_name[20];

       char chat_data[MAXSIZE];

      

       bzero(&chat_data,sizeof(chat_data));

       bzero(&peer_name,sizeof(peer_name));

      

       printf("请选择聊天对象:\n");

       scanf("%s",peer_name);

 

       while(getchar() != '\n'); 

       //usleep(100000);//延时下

       printf("-----------------正在与《%s》聊天-------------------\n",peer_name);

       while(1){

              printf("请输入聊天内容(按回车键发送):\n");

              printf("-----输入quit退回主界面-----\n");

              fgets(chat_data,sizeof(chat_data),stdin);

 

              if(strncmp(chat_data,"quit",4) == 0)

                            break;

              send_sig(myname,peer_name,chat_data,serv_addr,CHAT_PRI);

 

              printf("--------------------\n");

       }

 

}

/*线程:接收群聊消息(广播)*/

void *chat_toall_recv()

{

       int ret = -1;

       int num = -1;

//     sock_fd = cli_fd;

 

       struct msg rcv_buf;

       /*获取本机IP
并分配一个端口*/

       struct hostent *h_info;

       struct in_addr **p_addr;

       h_info = gethostbyname("ubuntu");

       p_addr = ((struct in_addr **)(h_info->h_addr_list));

 

       struct sockaddr_in self_addr;

       memset(&self_addr,0,sizeof(self_addr));

       self_addr.sin_family = AF_INET;

       self_addr.sin_port = htons(17891);

       self_addr.sin_addr.s_addr = htonl(INADDR_ANY);

       struct ip_mreq group;

       bzero(&group,sizeof(group));

       group.imr_multiaddr.s_addr = inet_addr("224.100.100.100");

       group.imr_interface = *(*p_addr);

       /*允许地址重用*/

       ret = setsockopt(sock_fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&group,sizeof(group));

       if(ret < 0){

              perror("setsockopt to ADD_MEMBERSHIP");

              exit(1);

       }

       ret = bind(sock_fd,(struct sockaddr *)&self_addr, sizeof(self_addr));

       if(ret < 0){

              perror("bind");

              exit(1);

       }

       while(1){

              //printf("等待接收群聊消息\n");

              ret = recvfrom(sock_fd,&rcv_buf,sizeof(rcv_buf),0,NULL,NULL);

              //printf("新的群聊消息\n");

              if(ret < 0){

                     perror("recvfrom");

                     exit(1);

              }

              rcv_buf.data[ret - sizeof(rcv_buf.type)-sizeof(rcv_buf.self_name)-sizeof(rcv_buf.dst_name)] = '\0';

              printf("=====《群聊》消息来自<%s>:\n",rcv_buf.self_name);

              printf("--------------------------\n");

              printf("消息内容:%s",rcv_buf.data);

             

       }

 

}

/*发送群聊消息,其实跟饲料消息基本一样的,消息类型不一样而已*/

void chat_toall(void)

{

       char chat_data[MAXSIZE];  

       bzero(&chat_data,sizeof(chat_data));

       printf("--------------------------------------------------------\n");

       printf("---------------<正在与所有在线用户聊天>-----------------\n");

       while(getchar() != '\n'); 

       while(1){

              printf("请输入聊天(群聊)内容(按回车键发送):\n");

              printf("-----输入quit退回主界面-----\n");

              fgets(chat_data,sizeof(chat_data),stdin);

 

              if(strncmp(chat_data,"quit",4) == 0)

                            break;

 

              send_sig(myname,NULL,chat_data,serv_addr,CHAT_ALL);

       }

 

}

/*线程:接收文件*/

void *recv_file(void *file_name)

{

       char download_path[80] = "/home/file_download/";

 

       int file_fd = -1;

       int recv_fd = -1;

       int new_fd = -1;

       int ret = -1;

       int num = -1;

       char buf[BUFSIZ];

       struct sockaddr_in file_addr;

       //printf("文件名:%s\n",(char *)file_name);

 

       strcat(download_path,(char *)file_name);

       file_fd = open(download_path, O_WRONLY|O_CREAT,0666);

       if(file_fd < 0){

              perror("open");

              pthread_exit(NULL);

       }

 

       recv_fd = socket(AF_INET,SOCK_STREAM,0);

       if (recv_fd < 0){

              perror("socket");

              pthread_exit(NULL);

       }

       int on = 1;

       ret = setsockopt(recv_fd,SOL_SOCKET,SO_REUSEADDR,(void *)&on,sizeof(on));

       if(ret < 0){

              perror("setsockopt to SO_REUSEADDR");

              pthread_exit(NULL);

       }

 

       struct hostent *h_info;

       struct in_addr **p_addr;

       h_info = gethostbyname("ubuntu");

       p_addr = ((struct in_addr **)(h_info->h_addr_list));

 

       bzero(&file_addr,sizeof(struct sockaddr));

       file_addr.sin_family = AF_INET;

       file_addr.sin_port = htons(12345);

       file_addr.sin_addr = *(*p_addr);

       //printf("\n下载数据至地址addr   :%s(%d)\n",inet_ntoa(file_addr.sin_addr),ntohs(file_addr.sin_port));

      

       ret = bind(recv_fd,(struct sockaddr *)&file_addr, sizeof(struct sockaddr));

       if(ret < 0){

              perror("bind");

              pthread_exit(NULL);

       }

       ret = listen(recv_fd,8);

       if(ret < 0){

              perror("listen");

              pthread_exit(NULL);

       }

      

       new_fd = accept(recv_fd,NULL,NULL);

      

       while(1){

              bzero(&buf,sizeof(buf));

              ret = read(new_fd,buf,sizeof(buf));

              if(ret < 0){

                     perror("read");

                     pthread_exit(NULL);

              }

              if(ret == 0){

                     break;

              }

              if(ret > 0){

                     num = write(file_fd,buf,ret);

                     if(num < 0){

                            perror("write");

                            pthread_exit(NULL);

                     }

 

              }

       }

       printf("<%s>下载完成\n",(char *)file_name);

       printf("(文件保存路径为:/home/file_download/\n");

       close(file_fd);

       close(recv_fd);

       close(new_fd);

 

       pthread_exit(NULL);

}

/*发出下载请求并创建接收数据线程*/

void download(void)

{

       char file_name[64];

       printf("当前资源中心所有文件:\n");

       usleep(100000);

       /*此次接收文件列表*/

       printf("\n请选择一个文件下载:\n");

       scanf("%s",file_name);

       send_sig(myname,NULL,file_name,serv_addr,DOWNLOAD);

       if(pthread_create(&tid4,NULL,recv_file,(void *)file_name)){

              perror("pthread_create2");

              exit(1);

       }

       pthread_join(tid4,NULL);

      

}

/*发送文件*/

void *send_file( void *file_name)

{

       int file_fd = -1;

       int send_fd = -1;

       char buf[BUFSIZ];

       int ret = -1;

       int num = -1;

       int len = -1;

       struct  sockaddr_in file_addr;

 

       char file_path[80]="/home/file_centre/";

 

       strcat(file_path, (char *)file_name);

 

       file_fd = open(file_path,O_RDONLY);

       if(file_fd < 0){

              perror("open");

              printf("对不起,您选择有误!请重新进入上传模式。\n");

              pthread_exit(NULL);

       }

 

       send_fd = socket(AF_INET,SOCK_STREAM,0);

       if(send_fd < 0){

              perror("socket");

              pthread_exit(NULL);

       }

       struct hostent *h_info;

       struct in_addr **p_addr;

       h_info = gethostbyname("ubuntu");

       p_addr = ((struct in_addr **)(h_info->h_addr_list));

 

       bzero(&file_addr,sizeof(struct sockaddr));

       file_addr.sin_family = AF_INET;

       file_addr.sin_port = htons(54321);

       file_addr.sin_addr = *(*p_addr);

       usleep(200000);

       ret = connect(send_fd,(struct sockaddr *)&file_addr,sizeof(struct sockaddr_in));

       if(ret < 0){

              perror("connect");

              pthread_exit(NULL);

       }

 

       len = lseek(file_fd,0L,SEEK_END);

       lseek(file_fd,0L,SEEK_SET);

 

       while(len > 0){

              bzero(&buf,sizeof(buf));

              ret = read(file_fd,buf,sizeof(buf));

              if(ret < 0){

                     perror("read");

                     pthread_exit(NULL);

              }

              num = write(send_fd,buf,ret);

              if(num < 0){

                     perror("write");

                     pthread_exit(NULL);

              }

       }

       printf("文件上传成功!\n");

       pthread_exit(NULL);

}

 

/*下载文件*/

void upload(void)

{

       char download_path[80] = "/home/liaoye/file_download/";

       char file_name[64];

       DIR *dirp;

       struct dirent *E;

       pthread_t tid5 = -1;

 

       dirp = opendir(download_path);

       printf("您的文件夹:\n");

 

       while( (E = readdir(dirp) )!= NULL)

              printf("<%s>\t",E->d_name);

       printf("\n");

 

       printf("选择您要上传的文件:\n");

       scanf("%s",file_name);

 

       send_sig(myname,NULL,file_name,serv_addr,UPLOAD);

       if(pthread_create(&tid5,NULL,send_file,(void *)&file_name)){

              perror("pthread_create2");

              exit(1);

       }

       pthread_join(tid5,NULL);

 

 

}

 

int main(void)

{

       void myhandle(int signum);

       signal(SIGINT,myhandle);

       struct msg mymsg;

       char ch;

       int on = 1;

       int ret = -1;

       char chat_data[MAXSIZE];

       char log[] = "上线了。\n";

       bzero(&chat_data,sizeof(chat_data));

       pthread_t tid1;

       pthread_t tid2;

       pthread_t tid3;

 

       bzero(&serv_addr,sizeof(struct sockaddr));

       serv_addr.sin_family = AF_INET;

       serv_addr.sin_port = htons(7890);

       serv_addr.sin_addr.s_addr = inet_addr("192.168.7.117");

 

 

       cli_fd = udp_link();

 

       sock_fd = udp_link();//组播套接字

 

       ret = setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,(void *)&on,sizeof(on));

       if(ret < 0){

              perror("setsockopt to SO_REUSEADDR");

              exit(1);

       }

       printf("\n");

       system("clear");

       printf("********************************************************\n");

       printf("***********************欢迎使用**********************\n");

       printf("********************************************************\n");

       printf("\n======================用户 
登录======================\n");

       printf("--------------------------------------------------------\n");

       printf("请输入您的用户名:\n");

       scanf("%s",myname);

       strcpy(chat_data,myname);

       strcat(chat_data,log);

       send_sig(myname,NULL,NULL,serv_addr,LOG_IN);

 

       usleep(200000);

       printf("提示:登录成功!\n");

       printf("========================================================\n");

      

       /*登录后发送刷新在线用户列表并打印*/

       printf("当前在线用户:\n");

       send_sig(myname,NULL,NULL,serv_addr,REFRESH);

      

       send_sig(myname,NULL,chat_data,serv_addr,CHAT_ALL);

 

       if(pthread_create(&tid1,NULL,recv_chat_func,NULL) < 0){

              perror("pthread_create1");

              exit(1);

       }

       pthread_detach(tid1);

       if(pthread_create(&tid2,NULL,chat_toall_recv,NULL) < 0){

              perror("pthread_create2");

              exit(1);

       }

       pthread_detach(tid2);

        /*列出所有功能*/

       usleep(200000);

option: printf("\n********************************************************\n");

       printf("********************用户主界面**********************\n");

       printf("********************************************************\n");

       show_opt();

       scanf(" %c",&ch);

       printf("-----------------------------------------------

抱歉!评论已关闭.