完成select的服务器和客户端
//服务器
#include <stdio.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
#define ERR(msg) do{\
fprintf(stderr,"%d--",__LINE__);\
perror(msg);\
}while(0)
#define SER_PORT 7777
#define SER_IP "192.168.8.205"
int ser_init();
int main(int argc, const char *argv[])
{
char buf[128]="";
ssize_t res=0;
struct sockaddr_in cin;
struct sockaddr_in cin_arr[1020];
socklen_t addr=sizeof(cin);
int sfd=ser_init();
printf("服务器就绪\n");
//初始化读集合
fd_set rfds;
fd_set temp_fds;
FD_ZERO(&rfds);
FD_ZERO(&temp_fds);
FD_SET(0,&rfds);
FD_SET(sfd,&rfds);
int max_fd=sfd;
//开始IO多路复用
while(1)
{
//判断是否有文件描述符就绪
temp_fds=rfds;
if(select(max_fd+1,&temp_fds,NULL,NULL,NULL)<0)
{
ERR("select");
return -1;
}
for(int i=0;i<=max_fd;i++)
{
if(FD_ISSET(i,&temp_fds))
{
if(0==i)
{
printf("触发键盘输入\n");
int snd_fd;
scanf("%d %s",&snd_fd,buf);
while(getchar()!=10);
if(snd_fd>sfd && FD_ISSET(snd_fd,&rfds))
{
if(send(snd_fd,buf,sizeof(buf),0)<0)
{
ERR("send");
return -1;
}
}
}
else if(i==sfd)
{
printf("触发客户端连接\n");
int nfd=accept(sfd,(struct sockaddr*)&cin,&addr);
if(nfd<0)
{
ERR("accept");
return -1;
}
printf("%d号客户端连接成功\n",nfd);
cin_arr[nfd]=cin;
FD_SET(nfd,&rfds);
max_fd=max_fd>nfd?max_fd:nfd;
}
else
{
printf("触发客户端交互\n");
bzero(buf,sizeof(buf));
res=recv(i,buf,sizeof(buf),0);
if(res<0)
{
ERR("recv");
return -1;
}
else if(0==res)
{
printf("%d客户端退出\n",i);
close(i);
FD_CLR(i,&rfds);
for(int j=max_fd;j>0;j--)
{
if(FD_ISSET(j,&rfds))
{
max_fd=j;
break;
}
}
}
else
{
printf("[%s:%d] %s\n",inet_ntoa(cin_arr[i].sin_addr),\
ntohs(cin_arr[i].sin_port),buf);
}
}
}
}
}
close(sfd);
return 0;
}
int ser_init()
{
//创建套接字
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
ERR("socket");
return -1;
}
//设置端口允许重用
int a=1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&a,sizeof(a))<0)
{
ERR("setsockopt");
return -1;
}
//绑定服务器IP和端口号
struct sockaddr_in sin={AF_INET,htons(SER_PORT),inet_addr(SER_IP)};
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR("bind");
return -1;
}
//将套接字设置为被动监听状态
if(listen(sfd,128)<0)
{
ERR("listen");
return -1;
}
return sfd;
}
//客户端
#include <stdio.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
#define ERR(msg) do{\
fprintf(stderr,"%d--",__LINE__);\
perror(msg);\
}while(0)
#define SER_PORT 7777
#define SER_IP "192.168.8.205"
int main(int argc, const char *argv[])
{
//创建套接字
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
ERR("socket");
return -1;
}
//获取服务器IP和端口号
struct sockaddr_in sin={AF_INET,htons(SER_PORT),inet_addr(SER_IP)};
//连接到服务器
if(connect(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR("connect");
return -1;
}
printf("服务器连接成功\n");
char buf[128]="";
ssize_t res=0;
//初始化读集合
fd_set rfds;
fd_set temp_fds;
FD_ZERO(&rfds);
FD_ZERO(&temp_fds);
FD_SET(0,&rfds);
FD_SET(sfd,&rfds);
int max_fd=sfd;
//开始IO多路复用
while(1)
{
temp_fds=rfds;
//判断是否有文件描述符就绪
if(select(max_fd+1,&temp_fds,NULL,NULL,NULL)<0)
{
ERR("select");
return -1;
}
if(FD_ISSET(0,&rfds))
{
printf("触发键盘输入\n");
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
if(send(sfd,buf,sizeof(buf),0)<0)
{
ERR("send");
return -1;
}
printf("发送成功\n");
}
if(FD_ISSET(sfd,&rfds))
{
printf("触发接收数据\n");
bzero(buf,sizeof(buf));
res=recv(sfd,buf,sizeof(buf),0);
if(res<0)
{
ERR("recv");
return -1;
}
else if(0==res)
{
printf("服务器断开连接\n");
break;
}
printf("[%s:%d] %s\n",inet_ntoa(sin.sin_addr),\
ntohs(sin.sin_port),buf);
}
}
close(sfd);
return 0;
}
完成poll的客户端
#include <stdio.h>
#include <poll.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
#define ERR(msg) do{\
fprintf(stderr,"%d--",__LINE__);\
perror(msg);\
}while(0)
#define SER_PORT 7777
#define SER_IP "192.168.8.205"
int main(int argc, const char *argv[])
{
//创建套接字
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
ERR("socket");
return -1;
}
//获取服务器IP和端口号
struct sockaddr_in sin={AF_INET,htons(SER_PORT),inet_addr(SER_IP)};
//连接到服务器
if(connect(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR("connect");
return -1;
}
printf("服务器连接成功\n");
char buf[128]="";
ssize_t res=0;
int pres=0;
//初始化读集合
struct pollfd pfd[2];
pfd[0].fd=0;
pfd[0].events=POLLIN;
pfd[1].fd=sfd;
pfd[1].events=POLLIN;
//开始IO多路复用
while(1)
{
//判断是否有文件描述符就绪
pres=poll(pfd,2,-1);
if(pres<0)
{
ERR("poll");
return -1;
}
else if(pres==0)
{
printf("超时\n");
break;
}
if(pfd[0].revents & POLLIN)
{
printf("触发键盘输入\n");
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
if(send(sfd,buf,sizeof(buf),0)<0)
{
ERR("send");
return -1;
}
printf("发送成功\n");
}
if(pfd[1].revents & POLLIN)
{
printf("触发接收数据\n");
bzero(buf,sizeof(buf));
res=recv(sfd,buf,sizeof(buf),0);
if(res<0)
{
ERR("recv");
return -1;
}
else if(0==res)
{
printf("服务器断开连接\n");
break;
}
printf("[%s:%d] %s\n",inet_ntoa(sin.sin_addr),\
ntohs(sin.sin_port),buf);
}
}
close(sfd);
return 0;
}
3. 项目:基于TCP的文件服务器(未完成)
项目需求:
1. 编写客户端和服务器
2. 客户端可以查看服务器端目录中的文件名 opendir readdir
3. 客户端可以从服务器中下载文件
4. 客户端可以上传文件给服务器
5. 多客户端同时在线
附加需求:
登录注册功能
报错信息比较少,登录时输入的是不存在的用户会直接进行注册的操作:(
//服务器
#include "inet.h"
#define SER_IP "192.168.8.205"
#define SER_PORT 7777
//服务器初始化
int ser_init();
//将目录下所有文件名放到一个文件中
int show_file(DIR *dp);
//接收客户端查看所有文件名的请求
int send_fname(int nfd);
//接收客户端下载文件的请求
int download(int nfd,char *buf);
//接收客户端上传文件的请求
int upload(int nfd,char *buf);
void *task(void *arg)//void *arg=(void *)&nfd
{
int nfd=*(int *)arg;
FILE *fp=fopen("./usr.txt","a+");
if(fp==NULL)
{
ERR("fopen");
return NULL;
}
char name[10]="";
char passwd[10]="";
char fname[10]="";
char fpasswd[10]="";
int flag=0;
char msg[128]="";
msg[0]='1';
char buf[512]="";
ssize_t res=0;
//接收用户输入的账号和密码
if(recv(nfd,name,sizeof(name),0)<0)
{
ERR("recv");
return NULL;
}
if(recv(nfd,passwd,sizeof(passwd),0)<0)
{
ERR("recv");
return NULL;
}
//判断该用户是否已注册
while(1)
{
if(fscanf(fp,"%s %s",fname,fpasswd)==EOF)
{
if(errno==0)
{
break;
}
else
{
ERR("fscanf");
return NULL;
}
}
printf("name=%s fname=%s\n",name,fname);
printf("passwd=%s fpasswd=%s\n",passwd,fpasswd);
if(strcmp(fname,name)==0)//
{
flag=1;
if(strcmp(fpasswd,passwd)==0)
{
strcpy(msg+1,"login success");
//发送用户登陆成功的信息
if(send(nfd,msg,sizeof(msg),0)<0)
{
ERR("send");
return NULL;
}
while(1)
{
bzero(buf,sizeof(buf));
res=recv(nfd,buf,sizeof(buf),0);
if(res<0)
{
ERR("recv");
return NULL;
}
else if(res==0)
{
printf("%d号客户端退出\n",nfd);
break;
}
if(buf[0]=='1')//接收到查看文件请求
{
send_fname(nfd);
}
else if(buf[0]=='2')//接收到下载文件请求
{
download(nfd,buf);
}
else if(buf[0]=='3')//接收到上传文件请求
{
upload(nfd,buf);
}
}
}
else
{
strcpy(msg,"passwd error\nplease input again");
//发送密码错误的信息
if(send(nfd,msg,sizeof(msg),0)<0)
{
ERR("send");
return NULL;
}
break;
}
}
}
if(flag==0)
{
strcpy(msg,"user does not exist\nplease register");
//发送用户不存在的信息
if(send(nfd,msg,sizeof(msg),0)<0)
{
ERR("send");
return NULL;
}
bzero(msg,sizeof(msg));
res=recv(nfd,msg,sizeof(msg),0);
if(res<0)
{
ERR("recv");
return NULL;
}
fprintf(fp,"%s\n",msg);
}
fclose(fp);
close(nfd);
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
int sfd=ser_init();
printf("服务器就绪\n");
//打开该服务器所在的目录
DIR *dp=opendir("./");
if(dp==NULL)
{
ERR("opendir");
return -1;
}
show_file(dp);
struct sockaddr_in cin;
socklen_t addr=sizeof(cin);
while(1)
{
//获取成功连接到服务器的客户端信息
int nfd=accept(sfd,(struct sockaddr*)&cin,&addr);
if(nfd<0)
{
ERR("accept");
return -1;
}
printf("%d号客户端连接成功\n",nfd);
//创建多线程
pthread_t tid;
pthread_create(&tid,NULL,task,(void *)&nfd);
if(pthread_create<0)
{
ERR("pthread_create");
return -1;
}
pthread_detach(tid);
}
close(sfd);
closedir(dp);
return 0;
}
int ser_init()
{
//创建套接字
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
ERR("socket");
return -1;
}
//设置端口允许重用
int a=1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&a,sizeof(a))<0)
{
ERR("setsockopt");
return -1;
}
//绑定服务器IP和端口号
struct sockaddr_in sin={AF_INET,htons(SER_PORT),inet_addr(SER_IP)};
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR("bind");
return -1;
}
//设置套接字为被动监听状态
if(listen(sfd,128)<0)
{
ERR("listen");
return -1;
}
return sfd;
}
int show_file(DIR *dp)
{
int fd=open("./show_file.txt",O_WRONLY|O_CREAT|O_TRUNC,0774);
if(fd<0)
{
ERR("open");
return -1;
}
char buf[512]="";
while(1)
{
struct dirent *pa=readdir(dp);
if(pa==NULL)
{
if(errno==0)
{
break;
}
else
{
ERR("readdir");
return -1;
}
}
if(*pa->d_name!='.')
{
int res=sprintf(buf,"%s\n",pa->d_name);
if(write(fd,buf,res)<0)
{
ERR("write");
return -1;
}
}
}
close(fd);
return 0;
}
int send_fname(int nfd)
{
char data[512]="";
int fd=open("./show_file.txt",O_RDONLY);
if(fd<0)
{
ERR("open");
return -1;
}
if(read(fd,data,sizeof(data))<0)
{
ERR("read");
return -1;
}
if(send(nfd,data,sizeof(data),0)<0)
{
ERR("send");
return -1;
}
close(fd);
return 0;
}
int download(int nfd,char *buf)
{
char fname[20]="";
char data[512]="";
char msg[128]="";
msg[0]='7';
ssize_t read_res=0;
ssize_t send_res=0;
int flag=0;
FILE *fp=fopen("./show_file.txt","r");
if(fp==NULL)
{
ERR("fopen");
return -1;
}
while(1)
{
if(fscanf(fp,"%s",fname)==EOF)
{
if(errno==0)
{
break;
}
else
{
ERR("fscanf");
return -1;
}
}
if(strcmp(buf+1,fname)==0)
{
flag=1;
strcpy(msg,"filename correct");
if(send(nfd,msg,sizeof(msg),0)<0)
{
ERR("send");
return -1;
}
int fd=open(fname,O_RDONLY);
if(fd<0)
{
ERR("open");
return -1;
}
while(1)
{
read_res=read(fd,data,sizeof(data));
if(read_res<0)
{
ERR("read");
return -1;
}
send_res=send(nfd,data,read_res,0);
if(send_res<0)
{
ERR("send");
return -1;
}
else if(send_res<512)
{
break;
}
}
close(fd);
break;
}
}
if(flag==0)
{
strcpy(msg+1,"filename error");
if(send(nfd,msg,sizeof(msg),0)<0)
{
ERR("send");
return -1;
}
}
fclose(fp);
return 0;
}
int upload(int nfd,char *buf)
{
ssize_t res_recv=0;
ssize_t res_wr=0;
char data[512]="";
int fd=open(buf+1,O_WRONLY|O_CREAT|O_TRUNC,0774);
{
if(fd<0)
{
ERR("open");
return -1;
}
}
while(1)
{
bzero(data,sizeof(data));
res_recv=recv(nfd,data,sizeof(data),0);
if(res_recv<0)
{
ERR("recv");
return -1;
}
res_wr=write(fd,data,res_recv);
if(res_wr<0)
{
ERR("write");
return -1;
}
else if(res_wr<512)
{
break;
}
}
close(fd);
return 0;
}
//客户端
#include "inet.h"
#define SER_IP "192.168.8.205"
#define SER_PORT 7777
//查看服务器所在目录的所有文件
int show_file(int sfd);
//下载文件
int download(int sfd);
//上传文件
int upload(int sfd);
int main(int argc, const char *argv[])
{
//创建套接字
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
ERR("socket");
return -1;
}
//连接服务器
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(SER_PORT);
sin.sin_addr.s_addr=inet_addr(SER_IP);
if(connect(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR("connect");
return -1;
}
printf("服务器连接成功\n");
ssize_t res=0;
char buf[128]="";
char name[10]="";
char passwd[10]="";
printf("请输入用户名:");
scanf("%s",name);
while(getchar()!=10);
if(send(sfd,name,sizeof(name),0)<0)
{
ERR("send");
return -1;
}
printf("请输入密码:");
scanf("%s",passwd);
while(getchar()!=10);
if(send(sfd,passwd,sizeof(passwd),0)<0)
{
ERR("send");
return -1;
}
//接收服务器发来的信息并进行相应操作
if(recv(sfd,buf,sizeof(buf),0)<0)
{
ERR("recv");
return -1;
}
if(buf[0]=='1')
{
printf("%s\n",buf+1);
while(1)
{
printf("1---查看\n");
printf("2---下载\n");
printf("3---上传\n");
printf("4---退出\n");
printf("请输入:");
char ch=getchar();
while(getchar()!=10);
switch(ch)
{
case '1':show_file(sfd);break;
case '2':download(sfd);break;
case '3':upload(sfd);break;
case '4':goto END;break;
default:printf("输入错误\n");
}
printf("请输入任意字符清屏:");
while(getchar()!=10);
system("clear");
}
}
else
{
printf("%s\n",buf);
bzero(name,sizeof(name));
bzero(passwd,sizeof(passwd));
printf("请输入用户名:");
scanf("%s",name);
while(getchar()!=10);
printf("请输入密码:");
scanf("%s",passwd);
while(getchar()!=10);
int size=sprintf(buf,"%s %s",name,passwd);
if(send(sfd,buf,size,0)<0)
{
ERR("send");
return -1;
}
printf("注册成功\n");
}
END:
//关闭文件描述符
close(sfd);
return 0;
}
int show_file(int sfd)
{
char buf[512]="";
buf[0]='1';
if(send(sfd,buf,1,0)<0)
{
ERR("sendto");
return -1;
}
if(recv(sfd,buf,sizeof(buf),0)<0)
{
ERR("recv");
return -1;
}
printf("%s",buf);
return 0;
}
int download(int sfd)
{
ssize_t res_rd=0;
ssize_t res_wr=0;
char msg[128]="";
char buf[512]="";
buf[0]='2';
printf("请输入要下载的文件:");
scanf("%s",buf+1);
while(getchar()!=10);
if(send(sfd,buf,sizeof(buf),0)<0)
{
ERR("send");
return -1;
}
if(recv(sfd,msg,sizeof(msg),0)<0)
{
ERR("recv");
return -1;
}
if(msg[0]!='7')
{
printf("%s\n",msg);
int fd=open(buf+1,O_WRONLY|O_CREAT|O_TRUNC,0774);
{
if(fd<0)
{
ERR("open");
return -1;
}
}
while(1)
{
bzero(buf,sizeof(buf));
res_rd=recv(sfd,buf,sizeof(buf),0);
if(res_rd<0)
{
ERR("recv");
return -1;
}
res_wr=write(fd,buf,res_rd);
if(res_wr<0)
{
ERR("write");
return -1;
}
else if(res_wr<512)
{
break;
}
}
close(fd);
}
else
{
printf("%s\n",msg+1);
printf("请重新输入文件名\n");
}
}
int upload(int sfd)
{
ssize_t res_rd=0;
ssize_t res_send=0;
char buf[512]="";
buf[0]='3';
printf("请输入要上传的文件:");
scanf("%s",buf+1);
//buf[strlen(buf)-1]=0;
while(getchar()!=10);
if(send(sfd,buf,sizeof(buf),0)<0)
{
ERR("send");
return -1;
}
int fd=open(buf+1,O_RDONLY);
{
if(fd<0)
{
ERR("open");
return -1;
}
}
while(1)
{
bzero(buf,sizeof(buf));
res_rd=read(fd,buf,sizeof(buf));
if(res_rd<0)
{
ERR("read");
return -1;
}
res_send=send(sfd,buf,res_rd,0);
if(res_send<0)
{
ERR("send");
return -1;
}
else if(res_send<512)
{
break;
}
}
close(fd);
return 0;
}