苏嵌教育工程实训(嵌入式硬件)

基于tcp协议的模拟聊天室程序:
/*
TCP特点:
1.面向连接
2.可靠
3.基于流
*/
/server.c/
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>

#define PORT 8888 //port端口
#define IP “127.0.0.1” //ip地址
#define SIZE 100 //最大允许100个客户端连接

#define REGIST 1 //注册
#define LOGIN 2 //登录
#define ONLINE 3 //在线
#define PRIVATE 4 //私聊
#define GROUP 5 //群聊
#define OFFLINE 6 //离线

struct Message
{
int fd; //当前用户fd
char text[1024]; //发送的消息
int tofd; //发送的对象
char toname[32]; //发送对象的昵称
char name[32]; //帐号
char passwd[32]; //密码
int online; //登录状态
int command; //功能序号

};
typedef struct Message msg; //重新定义结构体类型

struct Client
{
int fd;
char name[32]; //客户端昵称
char passwd[32]; //客户端密码
int online; //是否在线
};
typedef struct Client cli_info; //重新定义结构体类型

/*定义全局的结构体数组,保存客户端信息 */
cli_info info[SIZE];
int i = 0; //数组下标
int regist_num = 0; //已经注册的人数

void *ClienHandler(void arg)
{
msg m;
int k;
while (1)
{
/
不断接收来自客户端的消息 /
int ret = recv(
(int *)arg, &m, sizeof(m), 0);
if (-1 == ret)
{
perror(“recv”);
}
printf(“recv form %d \n”, *(int *)arg);
/根据结构体cammand成员调用不用功能的函数/
printf("%d\n", m.command);
switch (m.command)
{
case 1: /注册/
strcpy(info[regist_num].name, m.name);
strcpy(info[regist_num].passwd, m.passwd);
info[regist_num].online = 0;//离线
info[regist_num].fd = *(int )arg;
printf("%s注册成功!\n", m.name);
regist_num++;
break;
case 2: /登录/
for (k = 0; k<regist_num; k++)
{
if (!strcmp(m.name, info[k].name))
{
if (!strcmp(m.passwd, info[k].passwd))//匹配成功
{
memset(&m, 0, sizeof(m));
strcpy(m.text, “success”);
send(
(int )arg, &m, sizeof(m), 0);
info[k].online = 1;
break;
}
}
}
if (k == regist_num)
{
memset(&m, 0, sizeof(m));
strcpy(m.text, “failure”);
send(
(int )arg, &m, sizeof(m), 0);
}
break;
case 3: /查看在线用户/
m.online = 0;
for (k = 0; k<regist_num; k++)
{
if (info[k].online == 1)
{
strcat(m.text, info[k].name);
strcat(m.text, " ");
m.online++;
}
}
printf(“查看在线用户: %d\n”, m.online);
ret = send(
(int *)arg, &m, sizeof(m), 0);
printf(“arg: %d\n”, *(int )arg);
if (-1 == ret)
{
perror(“send”);
}
break;
case 4: /私聊/
for (k = 0; k<regist_num; k++)
{
if (!strcmp(m.toname, info[k].name))
{
ret = send(info[k].fd, &m, sizeof(m), 0);
if (-1 == ret)
{
perror(“send”);
}
break;
}
}
break;
case 5:/群聊/
for (k = 0; k<regist_num; k++)
{
if (info[k].online == 1)
{
ret = send(info[k].fd, &m, sizeof(m), 0);
if (-1 == ret)
{
perror(“send”);
}
}
}
break;
case 6: /下线/
for (k = 0; k<regist_num; k++)
{
if (
(int *)arg == info[k].fd)
{
info[k].online = 0;
break;
}
}
break;
}
}
}

int main()
{
int sockfd;
struct sockaddr_in server_addr; //保存服务器信息
int fd[SIZE] = { 0 };
/创建基于TCP的sockfd连接/
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
perror(“sockfd”);
exit(1);
}
memset(&server_addr, 0, sizeof(server_addr)); // 清空结构体
/* 填充结构体(服务器信息) /
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT); //设置端口号
server_addr.sin_addr.s_addr = inet_addr(IP);
/
绑定(把服务器信息绑定到socket) */
int ret = bind(sockfd, (struct sockaddr )&server_addr, sizeof(server_addr));
if (-1 == ret)
{
perror(“bind”);
exit(1);
}
/
设置监听队列 */
ret = listen(sockfd, 5);
if (-1 == ret)
{
perror(“listen”);
exit(1);
}
int j;
struct sockaddr_in client_addr; //保存客户信息
int length = sizeof(client_addr);
while (1)
{
for (j = 0; j <= i; j++)
{
if (fd[j] == 0)
break;
}
if (j > 100) //如果客户端连接数大于100
{
continue;
}
fd[j] = accept(sockfd, (struct sockaddr )&client_addr, &length);
if (-1 == fd[j])
{
perror(“accept”);
}
printf(“有客户端连接,fd %d port %d\n”, fd[j], client_addr.sin_port);
/
每一个客户端,启动一个线程 */
pthread_t tid;
ret = pthread_create(&tid, NULL, ClienHandler, &fd[j]);
if (-1 == ret)
{
perror(“pthread_create”);
}
i++;
}
return 0;
}

/*
TCP特点:
1.面向连接
2.可靠
3.基于流
*/
/client.c/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>

#define PORT 8888 //port端口
#define IP “127.0.0.1” //ip地址
#define SIZE 100 //最大允许100个客户端连接

pthread_t tid_send, tid_recv; //定义接收发送线程号

#define REGIST 1 //注册
#define LOGIN 2 //登录
#define ONLINE 3 //在线
#define PRIVATE 4 //私聊
#define GROUP 5 //群聊
#define OFFLINE 6 //离线

struct Message
{
int fd; //当前用户fd
char text[1024]; //发送的消息
int tofd; //发送的对象
char toname[32]; //发送对象的昵称
char name[32]; //帐号
char passwd[32]; //密码
int online; //登录状态
int command; //功能序号

};
typedef struct Message msg; //重新定义结构体类型

/服务器发送/
void *ClientSend(void *arg)
{
msg m;

while (1)
{
scanf("%s%d", m.text, &m.tofd); //获取发送的信息以及发送的对象
/*发送给服务器 /
int ret = send(
(int *)arg, &m, sizeof(m), 0);
if (-1 == ret)
{
perror(“send”);
}
memset(&m, 0, sizeof(m)); //清空结构体
}
}

/服务器接收/
void *ClientRecv(void arg)
{
msg m;
int old;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);//重复登录验证
while (1)
{
int ret = recv(
(int *)arg, &m, sizeof(m), 0);
if (-1 == ret)
{
perror(“recv”);
}
if (m.command == 3)
{
printf(“查看在线用户人数: \t\t%d\n”, m.online);
printf(“查看在线用户昵称: “);
}
printf(”\t\t%s\n”, m.text);
memset(&m, 0, sizeof(m));
}
}

/欢迎界面/
void welcome()
{
system(“clear”); //清屏
printf("\n\n\n");
printf("**** WE CHART ****\n");
sleep(2);
}

/目录/
void menu()
{
system(“clear”);
printf("\n\n\n");
printf("\t\t1.注册\n");
printf("\t\t2.登录\n");
}

/向服务器注册用户信息,参数fd表示socket文件描述符/
void regist(int fd)
{
msg m;
printf(“请输入用户名:”);
scanf("%s", m.name);
printf(“请输入密码:”);
scanf("%s", m.passwd);
m.command = 1; //注册
int ret = send(fd, &m, sizeof(m), 0);
if (-1 == ret)
{
perror(“send”);
}
printf(“注册成功”);
sleep(2);
}

/聊天目录/
void chat_menu()
{
system(“clear”); //清屏
printf("\t\t1、查看在线用户\n");
printf("\t\t2、私聊\n");
printf("\t\t3、群聊\n");
printf("\t\t4、退出\n");
}
/私聊/
void private_chat(int fd)
{
msg m;
printf(“请输入聊天对象: “);
scanf(”%s”, m.toname);
m.command = 4;

while (1)
{
scanf("%s", m.text);
if (!strcmp(m.text, “bye”))
{
break;
}
int ret = send(fd, &m, sizeof(m), 0);
if (-1 == ret)
{
perror(“send”);
}
}
}

/查看在线用户/
void ChaKan(int fd)
{
msg m;
m.command = ONLINE;
int ret = send(fd, &m, sizeof(m), 0);
if (-1 == ret)
{
perror(“send”);
}
sleep(2);
}

/群聊/
void QunTiao(int fd)
{
msg m;
m.command = GROUP;
while (1)
{
scanf("%s", m.text);
if (!strcmp(m.text, “bye”))
{
break;
}
int ret = send(fd, &m, sizeof(m), 0);
if (-1 == ret)
{
perror(“send”);
}
}
}

/聊天界面/
void chat(int fd)
{
msg m;
int choice;
while (1)
{
chat_menu(); //聊天界面菜单
scanf("%d", &choice);
if (choice == 1) //查看在线用户
{
ChaKan(fd);
}
else if (choice == 2) //私聊
{
private_chat(fd);
}
else if (choice == 3) //群聊
{
QunTiao(fd);
}
else if (choice == 4) //退出
{
m.command = OFFLINE;
int ret = send(fd, &m, sizeof(m), 0);
if (-1 == ret)
{
perror(“send”);
}
pthread_cancel(tid_recv);
break;
}
}
}

/登录,输入用户名和密码,如果用户名不存在或者密码错误,登录失败/
void login(int fd)
{
msg m;
printf("\t\t用户名: “);
scanf(”%s", m.name);
printf("\t\t密码 : “);
scanf(”%s", m.passwd);
m.command = 2; //登录
int ret = send(fd, &m, sizeof(m), 0);
if (-1 == ret)
{
perror(“send”);
}
memset(&m, 0, sizeof(m));
ret = recv(fd, &m, sizeof(m), 0);
if (-1 == ret)
{
perror(“recv”);
}
if (!strcmp(m.text, “success”))
{
printf("\t\t登录成功\n");
sleep(2);
/启动一个线程,负责接收服务器的消息/
ret = pthread_create(&tid_recv, NULL, ClientRecv, &fd);
if (ret != 0)
{
perror(“pthread_create”);
}
chat(fd); //聊天界面
}
else
{
printf("\t\t登录失败\n");
sleep(2);
}
}

int main()
{
int sockfd;
struct sockaddr_in server_addr;
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
perror(“socket”);
exit(1);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(IP);
/* 向服务器发起连接 */
int ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (-1 == ret)
{
perror(“connect”);
exit(1);
}
welcome();
int choice;
while (1)
{
menu();
scanf("%d", &choice);
switch (choice)
{
case 1:
regist(sockfd);//注册
break;
case 2:
login(sockfd);//登录
break;
default:
printf(“ERROR!\n”);
}
}
/*创建两个线程,用于接受和发送信息 */
ret = pthread_create(&tid_send, NULL, ClientSend, &sockfd);
if (ret != 0)
{
perror(“pthread_create”);
}
void *status;
pthread_join(tid_send, &status);
pthread_join(tid_recv, &status);
return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37135358/article/details/83181506