要求:
类似QQ的局域网通信工具
功能:
1、多个客户端进行通信(一对一) bingo!
2、用户的上线、离线提醒(广播) bingo!
3、每一个用户应该有上线的用户列表 bingo!
4、用户之间收发消息: 既然地址会有重用,无法解决,就采取收信息时过滤,或者发信息过滤
一对多(可以用组播,问题:在一个组播组中,有多个用户时端口号不同怎么去发送数据;其他)
5、一对一收发文件 bingo!
6、退出 bingo!
选做功能:
1、每个用户有自己的用户名和密码,需要登录 %50 bingo!
2、防止ctrl+c强制结束时的错误处理 %20 bingo!
3、实现好友列表,可以添加删除好友 自动添加,不能删除,多加个链可以实现
注:在实现上可以使用网状拓扑(udp, 只有一个程序),还可以使用C/S架构(tcp, 一个服务器程序,一个客户端程序)
一个程序 bingo!
head.h
#ifndef __HEAD_H_
#define __HEAD_H_
//文件IO
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//进程
#include
#include
#include
#include
#include
#include
#include
//线程
#include
//socket
#include
#include
#include "kernel_list.h"
#endif在这里插入代码片
kernal_list.h
#ifndef __KERNEL_LIST_H
#define __KERNEL_LIST_H
/* This file is from Linux Kernel (include/linux/list.h)
* and modified by simply removing hardware prefetching of list items.
* Here by copyright, credits attributed to wherever they belong.
* Kulesh Shanmugasundaram (kulesh [squiggly] isis.poly.edu)
*/
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions (“__xxx”) are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
/**
* container_of - cast a member of a structure out to the containing structure
*
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
//#define LIST_POISON1 ((void *) 0x00100100)
//#define LIST_POISON2 ((void *) 0x00200)
// 小结构体(内核链表)
struct list_head {
struct list_head *next;
struct list_head *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *new, // 要插入的节点
struct list_head *prev,// 前节点 before
struct list_head *next) // 后节点 after
{
next->prev = new; // 头插法 ,插在头节点之后
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add – add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head. 在指定的头后插入新的节点
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail – add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del – deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
*/
//函数实现仅仅是将节点从链表中取下,未释放
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = (void *) 0;
entry->prev = (void *) 0;
}
/**
* list_del_init – deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_move – delete from one list and add as another’s head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static inline void list_move(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add(list, head);
}
/**
* list_move_tail – delete from one list and add as another’s tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add_tail(list, head);
}
/**
* list_replace - replace old entry by new one
* @old : the element to be replaced
* @new : the new element to insert
*
* If @old was empty, it will be overwritten.
*/
static inline void list_replace(struct list_head *old,
struct list_head *new)
{
new->next = old->next;
new->next->prev = new;
new->prev = old->prev;
new->prev->next = new;
}
static inline void list_replace_init(struct list_head *old,
struct list_head *new)
{
list_replace(old, new);
INIT_LIST_HEAD(old);
}
/**
* list_empty – tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(struct list_head *head)
{
return head->next == head;
}
static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
/**
* list_splice – join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void list_splice(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head);
}
/**
* list_splice_init – join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static inline void list_splice_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head);
INIT_LIST_HEAD(list);
}
}
/**
* list_entry – get the struct for this entry
* @ptr: the &struct list_head pointer. 小结构体对应的地址
* @type: the type of the struct this is embedded in. 大结构体类型 (struct info)
* @member: the name of the list_struct within the struct. 小结构体在大结构体里面的成员名list
*///返回值为大结构体地址
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter. // p
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); \
pos = pos->next)
/**
* list_for_each_prev - iterate over a list backwards
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
//反向遍历
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); \
pos = pos->prev)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
pos为大结构体,head为大结构体中的小结构体成员
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_safe – iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif
在这里插入代码片
/* *********************************
***date:2020-6-5
***类似QQ的局域网通信工具(拓扑结构)
***name:[email protected]
**********************************/
#include "head.h"
struct client *head = NULL;
struct sockaddr_in recv_addr;
int socket_send;
int socket_rec;
char fun_port[20];
struct client
{
char ip[30];
unsigned short port;
int accept_fd;
char name[5];
struct list_head list;//内核链表小结构体
};//分号
/* 初始化链表 */
struct client *init_list(void)
{
struct client *head = malloc(sizeof(struct client));
if(head != NULL)
{
INIT_LIST_HEAD(&head->list);
}
return head;
}
//发消息
bool sen_msg(char *msg, unsigned short port)
{
struct list_head *pos;
struct client *tmp;
list_for_each(pos, &head->list)
{
tmp = list_entry(pos, struct client, list);
if(tmp->port == port)
{
write(tmp->accept_fd, msg, strlen(msg));
return true;
}
}
return false;
}
// void send_exit()
// {
// sendto(socket_send, "exit", 10, 0, (struct sockaddr *)&recv_addr, sizeof(recv_addr));
// }
//防止误按ctrl +c导致异常退出,对方不知道你是否在线的情况
void fun()
{
char tmp_port[30]={0};
sprintf(tmp_port,"exit:%s",fun_port);
sendto(socket_send, tmp_port, 30, 0, (struct sockaddr *)&recv_addr, sizeof(recv_addr));
exit(0);
}
void *routine(void *port)
{
/* 创建 套接字 */
int socket_udp = socket(AF_INET, SOCK_DGRAM, 0);
if(socket_udp == -1)
{
perror("socket");
return NULL;
}
/* 绑定IP地址和端口号 */
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(port));
printf("port: %s\n",(char*)port);
// 1、inet_addr
//server_addr.sin_addr.s_addr = inet_addr("192.168.14.203");
//2、inet_aton
//inet_aton("192.168.14.203", &server_addr.sin_addr);
//3、INADDR_ANY 代表主机的所有IP地址
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// inet_aton(tmp->ip, &server_addr.sin_addr);
//需要绑定的应该是自己的port套接字,加入监视用来看谁发来了消息
//问题:不能将得到的广播信息作为监听套接字绑定,试试创建新的单播udp socket
int ret = bind(socket_udp, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(ret == -1)
{
perror("bind");
// printf("LINE:%d\n",__LINE__);
// return NULL;
}
else
printf("bind sucess\n");
// 注册退出处理函数
// atexit(send_exit);
while(1)
{
// 好友列表
// /* 遍历链表*/
// list_for_each(pos, &head->list)
// {
// tmp = list_entry(pos, struct client, list);
// printf("好友列表\n");
// printf("[%s]\n", tmp->name);
// }
printf("1 发送消息给某人 2 发文件 3 创建群聊 4 下线 5 刷新好友列表\n");
int num;
char r_msg[100] = {0};
char w_msg[100] = {0};
char *str = NULL;
struct client *tmp;
struct list_head *pos;
int maxfd = 0;
/* 绑定自己的套接字 加入监视 ,接收输入*/
fd_set set;
FD_ZERO(&set);
FD_SET(socket_udp, &set);
maxfd = maxfd > socket_udp ? maxfd : socket_udp;
FD_SET(STDIN_FILENO, &set);
maxfd = maxfd > STDIN_FILENO ? maxfd : STDIN_FILENO;
int flag = 0;
/* 检测文件描述符是否有动作 */
select(maxfd+1, &set, NULL, NULL, NULL);
if(FD_ISSET(STDIN_FILENO, &set))//输入消息
{
scanf("%d",&num);
switch(num)
{
case 1:
{
printf("请输入消息格式 名字:消息\n");
read(0,w_msg,100);
// scanf(w_msg, 100, stdin);
// printf("what is read %s\n",w_msg);
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
// str = strstr(w_msg, ":");
char real_send[100]={0};
sprintf(real_send,"%s%s",(char *)port,w_msg);
list_for_each(pos, &head->list)
{
tmp = list_entry(pos, struct client, list);
if(strncmp(tmp->name,w_msg,4) == 0)
{
/* 创建 套接字 */
int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if(socket_fd == -1)
{
perror("socket");
return NULL;
}
printf("find [%s:%d] name %s\n", tmp->ip, tmp->port,tmp->name);
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(tmp->port);
server_addr.sin_addr.s_addr = inet_addr(tmp->ip);
/* 发数据 最后两个参数说明这个消息发送到谁*/
sendto(socket_fd,real_send, 100, 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
// printf("how much sendto %d\n",ret);
flag = 1;
break;
}
}
if(flag == 0)
printf("没找到该用户\n");
break;
}
case 4:
{ //进程结束,发送退出通知
char tmp_port[30]={0};
sprintf(tmp_port,"exit:%s",(char*)port);
sendto(socket_send, tmp_port, 30, 0, (struct sockaddr *)&recv_addr, sizeof(recv_addr));
exit(0);
}
break;
//发文件
case 2:
{
/* 创建 套接字 */
int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if(socket_fd == -1)
{
perror("socket");
return NULL;
}
char filename[50]={0};
/* 输入名字:文件名 不要写当前路径 */
printf("请输入消息格式 名字:file_文件名%s\n", filename);
read(0,filename,50); //read后面有\n,导致打开文件错误
//将末尾\n换成\0
for(unsigned int i = 0;i < strlen(filename);i++)
{
if(filename[i] == '\n')
{
filename[i] = '\0';
break;
}
}
char tmp_port[50]={0};
sprintf(tmp_port,"%s%s",(char*)port,filename);
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
// str = strstr(w_msg, ":");
list_for_each(pos, &head->list)
{
tmp = list_entry(pos, struct client, list);
if(strncmp(tmp->name,filename,4) == 0)
{
printf("find [%s:%d] name %s\n", tmp->ip, tmp->port,tmp->name);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(tmp->port);
server_addr.sin_addr.s_addr = inet_addr(tmp->ip);
/* 发数据 最后两个参数说明这个消息发送到谁*/
sendto(socket_fd,tmp_port, 50, 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
flag = 1;
break;
}
}
if(flag == 0)
{
printf("没找到该用户\n");
break;
}
/* 打开文件 */
str = strstr(filename, "_");
char filepath[20] = {0};
strcpy(filepath,str+1);
printf("filepathname : %s\n",filepath);
int file_fd = open(filepath, O_RDWR); //??
if(file_fd == -1)
{
perror("open() failed");
break;
}
else
printf("发送文件名成功,发送数据中\n");
/* 发送文件 */
int r, w;
int nw = 0;
char r_buf[100] = {0};
while(1)
{
r = read(file_fd, r_buf, sizeof(r_buf));
if(r == -1)
{
perror("read");
break;
}
usleep(10000);
w = sendto(socket_fd,r_buf, r, 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(w == 0)
{
printf("sendto finish\n");
break;
}
nw += w;
printf("sendto %d byte\n", nw);
}
}
case 5:
{
//好友列表
/* 遍历链表*/
printf("好友列表\n");
list_for_each(pos, &head->list)
{
tmp = list_entry(pos, struct client, list);
printf("[name:%s port:%d]\n", tmp->name,tmp->port);
}
}
break;
default:
printf("没有该选项,请重新输入\n");
break;
}
}
if(FD_ISSET(socket_udp, &set))//收消息
{
bzero(r_msg, 100);
struct sockaddr_in client_addr;
socklen_t size = sizeof(client_addr);
recvfrom(socket_udp, r_msg, 100, 0, (struct sockaddr *)&client_addr, &size);
//recv 端口号名字:信息
str = strstr(r_msg,":");
list_for_each(pos, &head->list)
{
tmp = list_entry(pos, struct client, list);
if(tmp->port == atoi(r_msg)) //不能用接收来的port用来判断
{
//接收文件格式 端口号name:file_路径/文件名
//默认存到当前路径下
if(strncmp(str+1,"file",4) == 0) //要收文件了
{
/* 选出文件名 */
// int k = 0;
int i = strlen(r_msg)-1;
for(;i >= 0;i--)
{
if(r_msg[i] != '/')
{
// k++;
}
else
break;
}
char filename[20] = {0};
strcpy(filename,r_msg+i+1);
printf("filename: %s\n",filename);
int file_fd = open(filename, O_RDWR|O_CREAT, 0777);
if(file_fd == -1)
{
perror("creat() failed:");
break ;
}
else
printf("创建%s文件名成功,接收数据中\n",filename);
/* 接收文件 */
int r, w;
int nr = 0;
char r_buf[100] = {0};
while(1)
{
bzero(r_buf,100);
r = recvfrom(socket_udp, r_buf, 100, 0, (struct sockaddr *)&client_addr, &size);
if(r == -1)
{
perror("recform");
break;
}
nr += r;
printf("read() %d byte\n", nr);
w = write(file_fd, r_buf, r);
if(w == -1)
{
perror("write() failed");
break ;
}
if( w == 0)
{
printf("write finish \n");
break;
}
}
}
else
printf("%s:%s\n",tmp->name,str+1);
break;
}
}
}
}
}
void link_to(char *name,char *tmp_port)
{
//注册信号处理函数ctrl+c
strcpy(fun_port,tmp_port);
signal(SIGINT,fun);
// 初始化头节点
head = init_list();
socket_send = -1;
socket_rec = -1;
struct list_head *pos, *n;
struct client *tmp;
char *str = NULL;
// char s_name[10]={0};
// strcpy(s_name,name);
/* 创建 套接字 */
socket_send = socket(AF_INET, SOCK_DGRAM, 0);
if(socket_send == -1)
{
perror("socket");
return ;
}
/* 设置可以发送广播 和端口重用*/
int on = 1;
setsockopt(socket_send, SOL_SOCKET,SO_BROADCAST, &on, sizeof(on));
setsockopt(socket_send, SOL_SOCKET,SO_REUSEADDR, &on, sizeof(on));
/* 设定广播地址和端口号 */
bzero(&recv_addr, sizeof(recv_addr));
recv_addr.sin_family = AF_INET;
recv_addr.sin_port = htons(50002);
recv_addr.sin_addr.s_addr = inet_addr("255.255.255.255");
char tmp_name[25]={0};
/* 发送用户名和单播通信端口号*/
sprintf(tmp_name,"%s:%s",tmp_port,name);
printf("tmp_name__%s\n",tmp_name);
sendto(socket_send,tmp_name, 20, 0, (struct sockaddr *)&recv_addr, sizeof(recv_addr));
//建立线程
pthread_t tid;
// (void *)tmp_port;
pthread_create(&tid,NULL,routine,(void *)tmp_port);
/* 创建广播接收 套接字 */
socket_rec = socket(AF_INET, SOCK_DGRAM, 0);
if(socket_rec == -1)
{
perror("socket");
return ;
}
/* 设置端口重用 */
int in = 1;
setsockopt(socket_rec, SOL_SOCKET,SO_REUSEADDR, &in, sizeof(in));
/* 绑定IP地址和端口号 */
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(50002);
// 1、inet_addr
//server_addr.sin_addr.s_addr = inet_addr("192.168.14.203");
//2、inet_aton
//inet_aton("192.168.14.203", &server_addr.sin_addr);
//3、INADDR_ANY 代表主机的所有IP地址
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(socket_rec, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(ret == -1)
{
perror("bind");
return ;
}
//问题;第三个用户上线后,只能接收到一个用户的广播,尝试多路复用
while(1)
{
int maxfd = 0;
/* 绑定套接字 加入监视 ,接收输入*/
fd_set set;
FD_ZERO(&set);
FD_SET(socket_rec, &set);
maxfd = maxfd > socket_rec ? maxfd : socket_rec;
/* 检测文件描述符是否有动作 */
select(maxfd+1, &set, NULL, NULL, NULL);
if(FD_ISSET(socket_rec, &set))//输入消息
{
char buf[30];
struct sockaddr_in send_addr;
socklen_t size = sizeof(send_addr);
/* 数据收 */
bzero(buf, 30);
recvfrom(socket_rec, buf, 30, 0, (struct sockaddr *)&send_addr, &size);
str = strstr(buf,":");
//判断是否为下线通知
if(strncmp(buf,"exit",4) == 0)
{
// printf("bufread: %s\n",buf);
list_for_each_safe(pos, n, &head->list)
{
tmp = list_entry(pos, struct client, list);
// printf("tmp->port: %d\n",tmp->port);
if(tmp->port == atoi(str+1))
{
printf("name %s已经下线\n",tmp->name);
//从链表中删除
list_del(&tmp->list);
break;
}
}
continue;
}
/* 接收上线通知,判断是否是新用户,新的话将将对端IP和端口号和名字存入链表中,并发送自己的在线通知给其他人*/
/*遍历链表*/
int flag = 0;
list_for_each_safe(pos, n, &head->list)
{
tmp = list_entry(pos, struct client, list);
if(strcmp(tmp->name,str+1) == 0)
{
flag = 1;
}
}
// printf("str+1 : %s\n",str+1);
// printf("tmp_port : %s\n",tmp_port);
if(atoi(tmp_port) == atoi(buf))
flag = 1;
if(flag == 0)
{
//创建套接字绑定端口等信息用做单播通信
printf("form [%s:%d] name %s已经上线\n", inet_ntoa(send_addr.sin_addr), ntohs(send_addr.sin_port), buf);
struct client *new = calloc(1, sizeof(struct client));
if(new != NULL)
{
strcpy(new->ip, inet_ntoa(send_addr.sin_addr));
new->port = atoi(buf);
// new->accept_fd = socket_udp;
str = strstr(buf,":");
strcpy(new->name,str+1);
// port++;
}
// /* 添加到链表中 */
list_add_tail(&new->list, &head->list);
//发送自己的在线通知给其他人
// usleep(10000);
sendto(socket_send,tmp_name, 30, 0, (struct sockaddr *)&recv_addr, sizeof(recv_addr));
}
}
}
/* 关闭套接字文件描述符 */
shutdown(socket_rec, 2);
shutdown(socket_send, 2);
}
int main(int argc,char **argv)
{
int num;
int fd_open;
int ret;
if(argc != 2)
{
printf("请输入./link 单播端口起始号");
return 0;
}
while(1)
{
while(1)
{
printf("1 注册 2 登录 3 关闭\n");
ret = scanf("%d",&num);
if (ret != 1)
{
continue;
}
else
break;
}
if(num == 3)
return 0;
switch(num)
{
case 1:
{
char name[5] = {0};
while(1)
{
printf("请输入4位数用户名\n");
scanf("%s",name);
if(strlen(name) == 4)
break;
bzero(name,5);
}
//打开或新建一个文件
fd_open = open("../image/name.txt",O_RDWR | O_CREAT,0777);
//先读判断用户名是否存在
char buf[5] = {0};
while(1)
{
read(fd_open,buf,5);
//到文件末尾且没有相同的用户名 表示可以注册
if(strcmp(buf,name) != 0 && read(fd_open,buf,5) == 0)
{
printf("用户名未用,可以使用\n");
int ret_w = write(fd_open,name,5);
if(ret_w == 5)
{
printf("注册成功,可以登录\n");
close(fd_open);
}
break;
}
//若有相同的,则需要重新注册
else if(strcmp(buf,name) == 0)
{
printf("用户名已存在,请重新注册\n");
close(fd_open);
break;
}
bzero(buf,5);
}
}
break;
case 2:
{
fd_open = open("../image/name.txt",O_RDWR | O_CREAT,0777);
char name[5] = {0};
char buf[5] = {0};
while(1)
{
printf("请输入4位用户名\n");
scanf("%s",name);
if(strlen(name) == 4)
break;
bzero(name,5);
}
while(1)
{
int ret_r = read(fd_open,buf,5);
if(strcmp(buf,name) == 0)
{
printf("登录成功\n");
//进入函数
printf("__%s\n",argv[1]);
link_to(name,argv[1]);
}
bzero(buf,5);
if(ret_r == 0)
{
printf("输入的用户不存在,请注册\n");
close(fd_open);
break;
}
}
}
break;
default:
printf("没有这个选项,请重新输入\n");
break;
}
}
return 0;
}在这里插入代码片