项目要求
项目实现分析
思维导图
1.基于tcp支持多客户端连接
所以要创建tcp并发服务器和一个tcp客户端,我选择tcp多线程并发服务器主线程用来连接客户端,子线程用来处理客户但请求
2.登陆注册功能,不能重复登录注册
创建一个用户表usr,包含用户名和密码。
不能重复注册,将用户名设为主键
不能重复登录,所以要再加一个标志位flag,用来判断用户是否在线,flag=1表示在线,flag=0表示离线,用户登陆前需判断此账号是否已经在线。登录成功将flag置1,用户下线将flag置0。
为了防止服务器意外退出,但其在线用户flag还未置零,所以每次重启服务器前要将所有用户flag置零。
3.将dict.txt导入数据库,单词查询,历史记录功能
第一次服务器应该创建词典表dict,将dict.txt导入,包含单词和意思,防止因为多次启动服务器而导致多次导入词典造成数据重复,导入词典之前应该先判断是否已经存在该表
单词查询,先判断用户输入的是中文还是英文,中文需要用到模糊查找
历史记录功能,创建历史表history,包含用户名,查找内容,查找时间。
用户名和内容可以通过用户在查找的时候一并发送给服务器,所以客户端要记录登录成功时候的用户名,查找时间可以写一个获取当前时间的函数来获取。
完整代码
头文件
head.h
#ifndef __HEAD_H__
#define __HEAD_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/select.h>
#include <poll.h>
#include <errno.h>
#include <sqlite3.h>
#define PRINT_ERR(msg) \
do{\
fprintf(stderr,"line:%d ",__LINE__);\
perror(msg);\
return -1;\
} while(0)
#define IF(i) if (argc != i) {\
printf("input error,try again\n");\
printf("usage: ./a.out srcfile destfile\n");\
return -1;\
}
#endif
此文件放在 /usr/include/目录下
服务器
tcptid_dict.c
#include <head.h>
#define PORT 8888
#define IP "192.168.10.159"
struct td
{
int newfd;
struct sockaddr_in cin_t;
};
sqlite3 *db;
void *callback(void *arg);
sqlite3 *init_dict();
int Users_logoff();
int init_tcpser(char *ip, int port);
int Tableisexist(char *name);
int handler(void *data, int argc, char **argv, char **azColName);
int dics_create();
int Login(int sfd);
int User_isonline(char *name);
int User_online(char *name);
int User_logoff(char *name);
int Register(int sfd);
int do_select(int sfd);
int do_history(char *name, char *news);
char *gettime();
int select_history(int sfd);
int main(int argc, const char *argv[])
{
//初始化数据库并导入电子词库
db = init_dict();
//初始化tcp服务器
int sfd = init_tcpser(IP, PORT);
struct td td_t;
socklen_t addrlen = sizeof(td_t.cin_t);
pthread_t tid;
while (1)
{
td_t.newfd = accept(sfd, (struct sockaddr *)&td_t.cin_t, &addrlen);
if (td_t.newfd < 0)
PRINT_ERR("accept");
printf("[%s:%d] newfd:%d 成功连接\n", inet_ntoa(td_t.cin_t.sin_addr), ntohs(td_t.cin_t.sin_port), td_t.newfd);
pthread_create(&tid, NULL, callback, (void *)&td_t);
pthread_detach(tid);
}
close(sfd);
return 0;
}
//子线程
void *callback(void *arg)
{
struct td *p = (struct td *)arg;
int newfd = p->newfd;
struct sockaddr_in cin_t = p->cin_t;
ssize_t res;
char buf[2];
while (1)
{
bzero(buf, sizeof(buf));
//先只读取前两个字节判断其功能,剩余消息在功能函数读取
res = recv(newfd, buf, 2, 0);
if (res == 0)
{
printf("客户端断开,关闭newfd:%d\n", newfd);
close(newfd);
return NULL;
}
switch (buf[1])
{
case 1:
printf("[%s:%d] newfd:%d请求注册\n", inet_ntoa(cin_t.sin_addr),
ntohs(cin_t.sin_port), newfd);
Register(newfd);
break;
case 2:
printf("[%s:%d] newfd:%d请求登录\n", inet_ntoa(cin_t.sin_addr),
ntohs(cin_t.sin_port), newfd);
Login(newfd);
break;
case 3:
printf("[%s:%d] newfd:%d请求查单词\n", inet_ntoa(cin_t.sin_addr),
ntohs(cin_t.sin_port), newfd);
do_select(newfd);
break;
case 4:
printf("[%s:%d] newfd:%d请求查询历史记录\n", inet_ntoa(cin_t.sin_addr),
ntohs(cin_t.sin_port), newfd);
select_history(newfd);
break;
case 5:
printf("[%s:%d] newfd:%d准备下线\n", inet_ntoa(cin_t.sin_addr),
ntohs(cin_t.sin_port), newfd);
recv(newfd, buf, sizeof(buf), 0);
User_logoff(buf);
break;
default:
break;
}
}
}
//初始化数据库
sqlite3 *init_dict()
{
if (sqlite3_open("sql.db", &db) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_open:%s\n", __LINE__, sqlite3_errmsg(db));
return NULL;
}
//将所有用户置于下线状态
Users_logoff();
//判断是否已经导入词典,存在则直接退出
if (Tableisexist("dict") == 0)
{
printf("电子词典库准备完毕\n");
return db;
}
//导入词典
dics_create();
printf("电子词典库准备完毕\n");
return db;
}
//将所有用户置于下线状态
int Users_logoff()
{
char sql[128] = "create table if not exists usr (name char primary key,password char,flag char);";
char *errmsg = NULL;
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
//将所有用户flag置零
sprintf(sql, "UPDATE usr SET flag='0';");
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
printf("%s\n",sql);
return 0;
}
//判断是否存在表,存在返回1,否则返回0
int Tableisexist(char *name)
{
char sql[128];
sprintf(sql, "SELECT COUNT(*) FROM sqlite_master where type ='table' and name ='%s';", name);
char *errmsg = NULL;
int flag = 0;
if (sqlite3_exec(db, sql, handler, (void *)&flag, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
return flag == 1 ? 0 : -1;
}
int handler(void *data, int argc, char **argv, char **azColName)
{
if (1 == argc)
{//存在表,则将flag置1
int iTableExist = atoi(*(argv));//如果存在表,*(argv)为"1"
if (data != NULL)
{
int *ptr = (int *)data;
*ptr = iTableExist;
}
}
return 0;
}
//导入词典
int dics_create()
{
printf("正在导入电子词典库,请稍后......\n");
char sql[128] = "create table if not exists dict (word_s char,explain_s char);";
char *errmsg = NULL;
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
FILE *fd = fopen("dict.txt", "r");
if (fd == NULL)
PRINT_ERR("fopen");
fseek(fd, 0, SEEK_END);
//记录文件大小
int fileLen = ftell(fd);
fseek(fd, 0, SEEK_SET);
char word[40];
char explain[60];
char buf[100];
int i;
int count = 0;
while (1)
{//取一行单词和意思
if (fgets(buf, sizeof(buf), fd) == NULL)
break;
//记录已读取的字节数
count += strlen(buf);
buf[strlen(buf) - 1] = 0;
for (i = 0; i < strlen(buf); i++)
{//防止单词中有一个空格的情况
if (buf[i] == ' ' && buf[i + 1] == ' ')
{
buf[i] = 0;
//提取单词
strcpy(word, buf);
break;
}
}
for (int j = i + 1; j < strlen(buf+i+1) + i + 1; j++)
{
if (buf[j] != ' ')
{//提取意思
strcpy(explain, buf + j);
break;
}
}
//导入
sprintf(sql, "INSERT INTO dict VALUES (\"%s\",\"%s\");", word, explain);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
//显示已导入百分比
printf("导入中..%%%.1f\r", (float)count / (fileLen / (100)));
fflush(stdout);
}
return 0;
}
//初始化tcp服务器
int init_tcpser(char *ip, int port)
{
//创建流式套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd < 0)
PRINT_ERR("socket");
//允许端口快速重用
int reuse = 1;
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
PRINT_ERR("setsockopt");
//填充地址信息的结构体,将IP和端口号绑定到套接字上
struct sockaddr_in sin_t;
sin_t.sin_family = AF_INET;
sin_t.sin_port = htons(port);
sin_t.sin_addr.s_addr = inet_addr(ip);
//绑定服务器的ip和端口
if (bind(sfd, (struct sockaddr *)&sin_t, sizeof(sin_t)) < 0)
PRINT_ERR("bind");
//将套接字设置为监听状态
if (listen(sfd, 128) < 0)
PRINT_ERR("listen");
printf("服务器初始化完成\n");
return sfd;
}
//客户端登录
int Login(int sfd)
{
ssize_t res;
char buf[50];
//读取用户名和密码
res = recv(sfd, buf, sizeof(buf), 0);
if (res < 0)
PRINT_ERR("recv");
printf("用户名:%s 密码:%s\n", buf, buf + strlen(buf) + 1);
char sql[128];
char *errmsg = NULL;
sprintf(sql, "select * from usr where name='%s';", buf);
char **pres;
int row, column;
if (sqlite3_get_table(db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
//row=0,即没有查询结果,不存在用户
if (row == 0)
{
//不存在该用户发送0
printf("不存在该用户\n");
buf[0] = 0;
if (send(sfd, buf, 1, 0) < 0)
PRINT_ERR("send");
}
//判断密码是否相同
else if (strcmp(pres[4], buf + strlen(buf) + 1) == 0)
{
//判断用户是否在线
if (User_isonline(buf) == 1)
{ //用户已在线发送3
buf[0] = 3;
if (send(sfd, buf, 1, 0) < 0)
PRINT_ERR("send");
return -1;
}
//将用户flag置1
User_online(buf);
//登录成功发送1
printf("登录成功\n");
buf[0] = 1;
if (send(sfd, buf, 1, 0) < 0)
PRINT_ERR("send");
}
else
{
//密码不对发送2
printf("%s\n", pres[3]);
printf("密码不正确\n");
buf[0] = 2;
if (send(sfd, buf, 1, 0) < 0)
PRINT_ERR("send");
}
return 0;
}
//判断用户是否在线,在线为1,反之为0
int User_isonline(char *name)
{
char sql[128];
sprintf(sql, "select flag from usr where name='%s';", name);
char *errmsg = NULL;
char **pres;
int row, column;
if (sqlite3_get_table(db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
//判断flag是否为1
if (strcmp(pres[1],"1")==0)
return 1;
else
return 0;
}
//用户上线,将flag置1
int User_online(char *name)
{
char sql[128];
sprintf(sql, "UPDATE usr SET flag='1' WHERE name='%s';", name);
char *errmsg = NULL;
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
return 0;
}
//用户下线,将flag置1
int User_logoff(char *name)
{
char sql[128];
sprintf(sql, "UPDATE usr SET flag='0' WHERE name='%s';", name);
char *errmsg = NULL;
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
return 0;
}
//客户端注册
int Register(int sfd)
{
ssize_t res;
char buf[50];
//读取用户名和密码
res = recv(sfd, buf, sizeof(buf), 0);
if (res < 0)
PRINT_ERR("recv");
printf("用户名:%s 密码:%s\n", buf, buf + strlen(buf) + 1);
char sql[128];
char *errmsg = NULL;
//导入用户表,默认flag为0
sprintf(sql, "INSERT INTO usr VALUES (\"%s\",\"%s\",\"%s\");", buf, buf + strlen(buf) + 1, "0");
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("注册失败,已有该用户\n");
buf[0] = 0;
//注册失败向客户端发送0
if (send(sfd, buf, 1, 0) < 0)
PRINT_ERR("send");
return -1;
}
printf("注册成功\n");
buf[0] = 1;
//注册成功向客户端发送1
if (send(sfd, buf, 1, 0) < 0)
PRINT_ERR("send");
return 0;
}
//查单词
int do_select(int sfd)
{
ssize_t res;
char buf[50];
char sql[128];
//读取用户名和要查询的内容
res = recv(sfd, buf, sizeof(buf), 0);
if (res < 0)
PRINT_ERR("recv");
printf("%s搜索'%s'\n", buf, buf + strlen(buf) + 1);
//将信息导入历史记录表
do_history(buf, buf + strlen(buf) + 1);
//判断是查询单词还是意思
if (buf[strlen(buf) + 1] >= 'a' && buf[strlen(buf) + 1] <= 'z')
sprintf(sql, "select * from dict where word_s=\"%s\";", buf + strlen(buf) + 1);
else
sprintf(sql, "select * from dict where explain_s LIKE \"%%%s%%\";", buf + strlen(buf) + 1);
char **pres;
char *errmsg = NULL;
int row, column;
if (sqlite3_get_table(db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
if (row == 0)
{ //没有查询到发送0
sql[0] = 0;
if (send(sfd, sql, 1, 0) < 0)
PRINT_ERR("send");
return 0;
}
for (int i = column; i + 1 < (row + 1) * column; i += 2)
{//将每条单词和意思合为一组,循环发送
sprintf(sql, "%-15s %s\n", pres[i], pres[i + 1]);
if (send(sfd, sql, sizeof(sql), 0) < 0)
PRINT_ERR("send");
}
//发送完,发送1表示发送完毕
sql[0] = 1;
if (send(sfd, sql, 1, 0) < 0)
PRINT_ERR("send");
sqlite3_free_table(pres);
return 0;
}
//将信息导入历史记录
int do_history(char *name, char *news)
{
char sql[128] = "create table if not exists history (name char,news char,time char);";
char *errmsg = NULL;
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
//获取时间
char *times = gettime();
sprintf(sql, "INSERT INTO history VALUES (\"%s\",\"%s\",\"%s\");", name, news, times);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
return 0;
}
//获取当前时间
char *gettime()
{
time_t ts;
struct tm *tm;
char *times = (char *)malloc(50);
ts = time(NULL);
tm = localtime(&ts);
sprintf(times, "%d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900,
tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
return times;
}
//客户端查询历史信息
int select_history(int sfd)
{
ssize_t res;
char buf[50];
char sql[128];
//读取用户名
res = recv(sfd, buf, sizeof(buf), 0);
if (res < 0)
PRINT_ERR("recv");
sprintf(sql, "select * from history where name='%s';", buf);
char **pres;
char *errmsg = NULL;
int row, column;
if (sqlite3_get_table(db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
if (row == 0)
{ //没有查询到发送0
sql[0] = 0;
if (send(sfd, sql, 1, 0) < 0)
PRINT_ERR("send");
return 0;
}
for (int i = 0; i + 2 < (row + 1) * column; i += 3)
{
sprintf(sql, "%-15s\t%-15s\t%-20s\t\n", pres[i], pres[i + 1], pres[i + 2]);
if (send(sfd, sql, sizeof(sql), 0) < 0)
PRINT_ERR("send");
}
//发送完,再次发送1表示发送完毕
sql[0] = 1;
if (send(sfd, sql, 1, 0) < 0)
PRINT_ERR("send");
sqlite3_free_table(pres);
return 0;
}
客户端
tcpcli_dict.c
#include <head.h>
#define PORT 8888
#define IP "192.168.10.159"
typedef void (*sighandler_t)(int);
void handler(int sig);
int init_tcpcli(char *ip, int port);
int LR_page(int sfd);
int main_page(int sfd);
int Login(int sfd, char *name);
int Register(int sfd);
int dict_select(int sfd);
int select_history(int sfd);
int end(int sfd);
char my_name[20];
int sfd;
int main(int argc, const char *argv[])
{
//初始化tcp客户端
sfd = init_tcpcli(IP, PORT);
//捕获ctrl+c信号
signal(2, handler);
LD: //登录注册页面
if (LR_page(sfd) == -1)
{ //返回值为-1,说明用户选择退出
goto END1;
}
//主页面
int a = main_page(sfd);
if (a == -1)
{ //返回值为-1,说明用户选择退出
goto END2;
}
else if (a == 1)
{ //返回值为1,说明用户选择返回,返回前先下线账号
end(sfd);
//返回上一级退出当前账号,将用户名清空
bzero(my_name,sizeof(my_name));
goto LD;
}
END2:
end(sfd);
END1:
//用户还未登录不用发送离线消息
close(sfd);
return 0;
}
//捕捉信号后的处理函数
void handler(int sig)
{
//判断用户是否已登录,还未登录不用发送离线消息
if (strlen(my_name) != 0)
end(sfd);
close(sfd);
exit(0);
}
//初始化客户端
int init_tcpcli(char *ip, int port)
{
//创建流式套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd < 0)
PRINT_ERR("socket");
struct sockaddr_in sin_t;
sin_t.sin_family = AF_INET;
sin_t.sin_port = htons(port);
sin_t.sin_addr.s_addr = inet_addr(ip);
if (connect(sfd, (struct sockaddr *)&sin_t, sizeof(sin_t)) < 0)
PRINT_ERR("connect");
printf("成功连接服务器[%s:%d]\n", inet_ntoa(sin_t.sin_addr), ntohs(sin_t.sin_port));
return sfd;
}
//登录注册页面
int LR_page(int sfd)
{
char c;
while (1)
{
system("clear");
printf("*******************\n");
printf("*******1.登录******\n");
printf("*******2.注册******\n");
printf("*******3.退出******\n");
printf("*******************\n");
printf("请输入>>>");
c = getchar();
while (getchar() != 10)
;
switch (c)
{
case '1':
c = Login(sfd, my_name);
break;
case '2':
Register(sfd);
break;
case '3':
return -1;
default:
printf("请输入正确的选项\n");
break;
}
if (c == 1)
{
printf("输入任意字符跳转>>>");
while (getchar() != 10)
;
break;
}
printf("输入任意字符清屏>>>");
while (getchar() != 10)
;
}
return 0;
}
//主页面
int main_page(int sfd)
{
while (1)
{
system("clear");
printf("**************************\n");
printf("*******1.查单词***********\n");
printf("*******2.查看历史记录******\n");
printf("*******3.返回上一级********\n");
printf("*******4.退出**************\n");
printf("**************************\n");
printf("请输入>>>");
char c = getchar();
while (getchar() != 10)
;
switch (c)
{
case '1':
dict_select(sfd);
break;
case '2':
select_history(sfd);
break;
case '3':;
return 1;
break;
case '4':
return -1;
break;
default:
printf("请输入正确的选项\n");
break;
}
printf("输入任意字符清屏>>>");
while (getchar() != 10)
;
}
return 0;
}
//查单词
int dict_select(int sfd)
{
char word[50];
char buf[128];
while (1)
{
system("clear");
printf("请输入要查找的单词或中文(输入#退出)\n");
scanf("%s", word);
if (word[0] == '#')
{
while (getchar() != 10)
;
return 0;
}
while (getchar() != 10)
;
//封装数据包,3代表查单词
int size = sprintf(buf, "%c%c%s%c%s%c", 0, 3, my_name, 0, word, 0);
if (send(sfd, buf, size, 0) < 0)
PRINT_ERR("send");
while (1)
{
if (recv(sfd, buf, sizeof(buf), 0) < 0)
PRINT_ERR("recv");
if (buf[0] == 0)
{
printf("无该单词\n");
break;
}
else if (buf[0] == 1)
{
printf("查询完毕\n");
break;
}
else
printf("%s", buf);
}
printf("输入任意字符清屏>>>");
while (getchar() != 10)
;
}
}
//查看历史记录
int select_history(int sfd)
{
char buf[128];
//封装数据包,4代表查记录
int size = sprintf(buf, "%c%c%s%c", 0, 4, my_name, 0);
if (send(sfd, buf, size, 0) < 0)
PRINT_ERR("send");
while (1)
{
if (recv(sfd, buf, sizeof(buf), 0) < 0)
PRINT_ERR("recv");
if (buf[0] == 0)
{
printf("无记录\n");
break;
}
else if (buf[0] == 1)
{
printf("查询完毕\n");
break;
}
else
printf("%s", buf);
}
return 0;
}
//登录
int Login(int sfd, char *my_name)
{
char name[20];
char password[30];
char buf[50];
printf("请输入用户名和密码\n");
printf("(用户名和密码用空格隔开)\n");
scanf("%s %s", name, password);
while (getchar() != 10)
;
//封装数据包,2代表登录
int size = sprintf(buf, "%c%c%s%c%s%c", 0, 2, name, 0, password, 0);
if (send(sfd, buf, size, 0) < 0)
PRINT_ERR("send");
if (recv(sfd, buf, 1, 0) < 0)
PRINT_ERR("recv");
if (buf[0] == 1)
{
strcpy(my_name, name);
printf("登录成功\n");
return 1;
}
else if (buf[0] == 0)
printf("不存在该用户\n");
else if (buf[0] == 2)
printf("密码不正确\n");
else if (buf[0] == 3)
printf("账号已在别处登录\n");
return 0;
}
//注册
int Register(int sfd)
{
char name[20];
char password[30];
char buf[50];
printf("请输入要注册的用户名和密码\n");
printf("(用户名和密码用空格隔开)\n");
scanf("%s %s", name, password);
while (getchar() != 10)
;
//封装数据包,1代表注册
int size = sprintf(buf, "%c%c%s%c%s%c", 0, 1, name, 0, password, 0);
if (send(sfd, buf, size, 0) < 0)
PRINT_ERR("send");
if (recv(sfd, buf, 1, 0) < 0)
PRINT_ERR("recv");
if (buf[0] == 1)
printf("注册成功\n");
else
printf("注册失败,已存在该用户\n");
return 0;
}
//下线
int end(int sfd)
{
char buf[50];
//封装数据包,5代表该用户下线
int size = sprintf(buf, "%c%c%s%c", 0, 5, my_name, 0);
if (send(sfd, buf, size, 0) < 0)
PRINT_ERR("send");
return 0;
}