聊天室程序

来源:互联网 发布:pla算法R语言实现 编辑:程序博客网 时间:2024/05/16 09:52

服务器

#include <stdio.h>

#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define SERVPORT 8081 //服务器端口号
#define BUFSIZE 200   //最大传输量
int main(int args, char *argv[]) 
{
int sockfd, bytesRec, i, j;
fd_set readfd;//定义一个由端口可读构成的端口集合
char filename[30], name[30], password[30], cmd[50], buf1[50], buf2[50];
char recv_buf[10000000];
char send_buf[BUFSIZE];
char file_buf[BUFSIZE];


memset(buf1, 0, sizeof(buf1));
memset(buf2, 0, sizeof(buf2));
struct sockaddr_in serv_addr;//连接前的初始化
struct hostent *host;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {//创建socket以及相应的错误处理
perror("socket创建出错!");
exit(1);
}


serv_addr.sin_family = AF_INET;//连接前的初始化工作
serv_addr.sin_port = htons(SERVPORT);
serv_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(serv_addr.sin_zero), 8);


printf("Please Enter Your Name: ");//用户输入用户名方便存入服务器端的“表”中
scanf("%s",name);
printf("Password: ");//提示用户输入密码。其实在本程序中根本没用到密码
scanf("%s", password);
memset(recv_buf, 0, BUFSIZE);




if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) < 0) {//建立连接以及相应的连接错误提示处理
perror("connect error!");
exit(1);
}


bytesRec = recv(sockfd, recv_buf, BUFSIZE, 0);//从服务器接受到登录成功提示以及接受失败处理
if( bytesRec == -1) {
perror("receive error!");
exit(1);
}


recv_buf[bytesRec] = '\0';
printf("%s", recv_buf);//回显接受到的消息,也就是回显服务器发送的本客户端成功登录的消息
send(sockfd, name, 30, 0);//将本用户的姓名发给服务器方便服务器储存到“表”中


while(1) { //服务器不断循环知道检测到有端口可读取、


FD_ZERO(&readfd); //将可读端口集合清空
FD_SET(sockfd, &readfd); //将和服务器简介的端口加入到可读集合中方便select()函数的调用
FD_SET(0, &readfd); //将标准输入(键盘输入)加入到此集合中方便select()监听


select(sockfd+1, &readfd, NULL, NULL, NULL);//调用select()函数
memset(recv_buf, 0, sizeof(recv_buf));
memset(send_buf, 0, sizeof(send_buf));


if (FD_ISSET(sockfd, &readfd)) //如果和服务器相连接的端口有东西可读则做相应的处理
{
if (-1 == (bytesRec =read(sockfd, recv_buf, sizeof(recv_buf))))//接受数据并作相应的接受错误处理
{
perror("read data error:");
close(sockfd);
exit(1);
}
printf("%s\n", recv_buf);
}
if ( FD_ISSET( 0, &readfd)) //如果标准输入有东西可读则做相应的处理
{
memset(send_buf, 0, sizeof(send_buf));
read(0, send_buf, sizeof(send_buf));//从标准输入读取命令到send_buf中
send_buf[strlen(send_buf) - 1] = '\0';
if(strncmp(send_buf,"!logoff\0", 8) == 0)//退出命令的处理
break;
send(sockfd, send_buf, strlen(send_buf), 0);//若是对话命令或者!list等其他命令在直接发送给服务器让服务器进行处理
}
}
close(sockfd);//关闭连接
return 0;

}


客户端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERPORT 8081//端口号
#define BACKLOG 10  //最大传输量




struct client_info//本人定义的结构体,用来储存用户的名字以及连接的端口号
{
char name[30];
int id; //储存每一个连接的端口号
};

int conn_amount; //储存当前系统连接数
struct client_info clients[10];//定义了个全局变量便于后面进程以及函数的访问
void init()//初始结构体数字以防储存登录用户信息的时候存入错误的信息
{
int i;
for(i = 0; i < BACKLOG; i++) {
memset(clients[i].name, 0, 30);
clients[i].id = 0;
}
}


void showclient()//本人写的一个调试函数便于在服务器窗口显示当前结构体数组里在线用户的情况有利于debug
{
int i;
printf("client amount: %d\n", conn_amount);
for (i = 0; i < BACKLOG; i++) {
printf("[%d]:%d  ", i, clients[i].id);
}
printf("\n\n");
}


void main(int args) 
{
printf("-------------------------------------------\r\n");
int sockfd, clientfd, ret, i, j, k, filetopos = -1;//记录文件传输时接受方用户最结构体数组中的下标
printf("-------------------------------------------\r\n");
socklen_t sin_size;
char name[30], buf[10000000], msgbuf[100];
fd_set readfd;//定义可读端口的集合方便后面select()函数运用
int isfind = 0;//后面判断文件传输或者发送消息时是否存在这么个用户用得到的标记变量
int ismsg = 0;//定义的一个变量来判断文件传输是否完成
struct timeval timeout; //定义select()函数内超时的变量
init();
struct sockaddr_in my_addr;
struct sockaddr_in client_addr;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {//创建服务器端口并且对付错误情况
perror("socket创建出错!");
exit(1);
}


my_addr.sin_family = AF_INET;//建立间接所需要初始化的变量
my_addr.sin_port = htons(SERPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero), 8);


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);
}
printf("-------------------------------------------\r\n");


int maxsock = sockfd;//得到当前连接用户中最大的端口号方便后面select()函数的查询
while(1) //服务器不断循环来监听端口是否有连接
{
FD_ZERO(&readfd);//每次循环都先清空可读端口集合
FD_SET(sockfd, &readfd);    //将服务器端口添加到集合中


timeout.tv_sec = 5000;//定义select()函数超时的时间
timeout.tv_usec = 0;


for (i = 0; i < BACKLOG; i++) 
{
if (clients[i].id != 0) 
{
FD_SET(clients[i].id, &readfd);
}
} //遍历结构体数组将在线的用户端口添加到可读端口集合中。
ret = select(maxsock + 1, &readfd, NULL, NULL, &timeout);//调用select()函数将端口此时有东西可读的端口都添加到集合中方便后面我们对发送过来的消息进行处理


printf("-------------------------------------------\r\n");
if (ret < 0) //对付select()函数错误的情况
{
perror("select");
break;
}
else if (ret == 0) //select()中的超时调用
{
printf("timeout\n");
continue;
}


for (i = 0; i < conn_amount; i++)//对连接的每个用户逐一的进行相应的处理
{
if (FD_ISSET(clients[i].id, &readfd))//判断如果当前端口在可读集合中说明有人向这个端口发送消息了系统相应的处理
{
memset(buf, 0, sizeof(buf));
ret = recv(clients[i].id, buf, sizeof(buf), 0);//接受消息到buf中
if (ret <= 0) //若ret<=0则说明有人登出做相应的处理
{        // client close
printf("client[%d] close\n", i);
close(clients[i].id);
FD_CLR(clients[i].id, &readfd);//将登出的端口移出集合
clients[i].id = 0;
conn_amount--;//修改在线用户连接数

else //否则则说明此端口有消息或命令发送过来我们要逐一分析处理
{        // receive data
//处理送过来的是对话命? printf("%s\r\n",buf);
if (conn_amount < BACKLOG) //靠靠靠靠靠靠靠靠靠靠靠靠? {
for(k = 0; k < 10; k++)
{
if(clients[k].id != 0)
{
send(clients[k].id,buf,strlen(buf),0);//靠靠靠靠? }
}
}
}
}
}


if (FD_ISSET(sockfd, &readfd))    // check whether a new connection comes
{
clientfd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);//尝试连接新的用户
if (clientfd <= 0) //错误连接处理
{
perror("accept\r\n");
continue;
}
if (conn_amount < BACKLOG) //若没达到最大连接数则安排一个空的下标给新连接的用户
{
for(k = 0; k < 10; k++)
{
if(clients[k].id == 0)
{
clients[k].id = clientfd;
break;
}
}
conn_amount++;//修改连接数
printf("new connection client[%d] %s:%d\n", conn_amount, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
send(clientfd, "[SERVER] You have loged on successfully !\n", 44, 0);//服务器回显登录成功
if (clientfd > maxsock)
{
maxsock = clientfd;//修改最大的端口数确保调用select()的正确性
}
}
else //连接达到最大数则返回错误信息
{
printf("max connections arrive, exit\n");
send(clientfd, "Too many clients connect the serve! Please try another time", 59, 0);
close(clientfd);
break;
}
}
}
for (i = 0; i < BACKLOG; i++) 
{
if (clients[i].id != 0) 
{
close(clients[i].id);
}
} //退出前断开所有的连接
exit(0);
}




原创粉丝点击