多线程异步非阻塞telnet c/s

Customed Telnet Server And Client

描述

这是sockets编程写的一个简单的telnet服务器,分为服务器和客户端两部分。服务器采用多线程异步套接字架构,对于来自客户端的连接会触发SIGIO信号,并将此连接交由新线程来处理。对于每个连接的客户端,服务器会维护一个套接字列表,SIGINT信号会触发服务器向所有在线的客户端发送一个LEAVE消息实现graceful-shutdown。客户端同样监听SIGINT信号,在客户端下线之前向服务器发送一个LEAVE消息。此外,还支持文本型的文件传送、服务器端支持日志记录、采用了简单的Ascii码循环移位加密、支持用户名和密码的登录认证等等。

编译

  • 服务器 make 会在目录下生成server二进制文件
  • 客户端 make 会在目录下生成client二进制文件

使用

  • 服务器 ./server port username password
  • 客户端 ./client domain/ip port username password [file]

功能

服务器支持多线程异步套接字架构

可支持多客户端同时连接且会话都为非阻塞模式

监听SIGIO,SIGINT,SIGPIP信号

SIGIO信号提供非阻塞支持,SIGINT信号提供紧急中断支持,SIGPIP信号提供异常下线支持

支持字符文件传送

可以传送字符型文件

支持加密

支持加密模块,可以应用各种加密方法。

支持graceful leave

服务器、客户端下线前会发送leave消息,实时通知对方

支持日志记录

服务器会记录客户端的登陆情况、执行的命令等。

flowchart

附图如下。

flowchart

server代码

ComServer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<stdio.h>
#include<netinet/in.h> //定义了struct sockaddr_in
#include <arpa/inet.h> //定义了inet_ntop函数
#include<stdlib.h>
int globalsock;
int ClientSockNumber=0; //在线客户端数量
int ClientSockList[255]={0}; //在线客户端套接字列表
int main(int argc,char *argv[])
{
print("\n欢迎访问Tyr.Chen自定义telnet服务器!",1);
if(argc!=4)
{
printf("使用方法:%s <端口> <用户名> <密码>\n",argv[0]);
exit(0);
}
int port=atoi(argv[1]);
int servsock=CreateSocket(argc,port); //创建套接字
set_password(argv[2],argv[3]); //设置密码
set_signal(); //设置信号
while(1)
{
puts("等待客户端响应...");
sleep(10);
}
}
CreateSocket.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<netinet/in.h> //定义了struct sockaddr_in
#include <arpa/inet.h> //定义了inet_ntop函数
#include<stdio.h>
#define servip "0.0.0.0" //监听所有ip
extern globalsock;
int CreateSocket(int argc,int port)
{
int servsock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); //创建socket
globalsock=servsock;
if(servsock<0)
massage("套接字创建失败!");
else
print("套接字创建成功!",1);
int recvbuff;
//设置套接字选项使得可以绑定处于TIME_WAIT状态的端口
struct sockaddr_in servAddr;
if(setsockopt(servsock,SOL_SOCKET,SO_REUSEADDR,&recvbuff,sizeof(recvbuff))<0)
massage("设置套接字选项失败!");
servAddr.sin_family=AF_INET;
servAddr.sin_port=htons(port);
int flag=inet_pton(AF_INET,servip,&servAddr.sin_addr.s_addr);
if(!flag)
massage("错误的IP地址!");
else if(flag<0)
massage("pton failed!");
flag=bind(servsock,(struct sockaddr *)&servAddr,sizeof(servAddr));
if(flag<0)
massage("地址绑定失败!");
else
print("地址绑定成功!",1);
flag=listen(servsock,SOMAXCONN); //SOMAXCONN常量定义了最大连接队列
if(flag<0)
massage("侦听失败!");
else
print("侦听成功!",1);
print("------------------",1);
printf("侦听地址 %s:%d 等待客户端连接 ...\n",servip,port);
return servsock;
}
serv_process.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<netinet/in.h> //定义了struct sockaddr_in
#include <arpa/inet.h> //定义了inet_ntop函数
#include<netdb.h> // 定义了 NI_MAXHOST & NI_MAXSERV
#include<time.h>
#define BUFSIZE 655350
#define COMRET 655350
FILE *fp;
extern int ClientSockNumber;
extern int ClientSockList[255];
//服务器返回的命令提示符,格式为:username@hostname:dirname[$|#]
struct servinfo{
char servPS [200];
};
char clntip[16];
void process(int sock,struct sockaddr_in clntAddr)
{
int byteRecv,byteSend;
char buffer[BUFSIZE];
FILE *stream;
char hostName[NI_MAXHOST];
char servName[NI_MAXSERV];
char ComRTN[COMRET];
time_t timep;
time(&timep);
char timeo[255];
strcpy(timeo,ctime(&timep)); //记录命令执行时间
timeo[strlen(timeo)-1]='\0';
if(inet_ntop(AF_INET,&clntAddr.sin_addr.s_addr,clntip,sizeof(clntip))!=NULL)
{
int rtnVal=getnameinfo((struct sockaddr *)&clntAddr,sizeof(clntAddr),hostName,sizeof(hostName),servName,sizeof(servName),0);
//getnameinfo反向解析客户端hostname
printf("与客户端%s(%s)开始会话\n",hostName,clntip);
fp=fopen("./server.log","a+");
//记录连接到日志
fprintf(fp,"%s\n--------------------------------------\n",ctime(&timep));
fprintf(fp,"与客户端%s(%s)的会话\n",hostName,clntip);
fclose(fp);
}
else
massage("无法获得客户端地址!");
struct servinfo local;
int ii=1;
getservinfo(&local);
send(sock,&local,sizeof(local),0); //发送PS1值
while(1)
{
fp=fopen("./server.log","a+");
memset(buffer,0,BUFSIZE);
memset(ComRTN,0,COMRET);
byteRecv=recv(sock,buffer,BUFSIZE,0);
decrypto(buffer);
if (byteRecv<0)
massage("接收失败");
if(!strcmp(buffer,"CHDFLAGOFLEAVING")) //此为客户端离开消息
{
printf("客户端'%s' 已经下线 ...\n",clntip);
printf("当前客户端数量:%d\n",--ClientSockNumber);
fprintf(fp,"客户端'%s'已下线 ...\n",clntip);
int j=0;
while(ClientSockList[j]!=sock)
j++;
while(ClientSockList[j]!=0) //不再维护该客户端套接字
{
ClientSockList[j]=ClientSockList[j+1];
j++;
}
pthread_exit(NULL);
}
if(!strcmp(buffer,"CHDFLAGOFFILE")) //客户端进入文件传输模式
{
recvfile(sock);
}
printf("[%s] %s\n",timeo,buffer); //记录时间和命令
fprintf(fp,"%d\t%s\n",ii++,buffer);
stream=popen(buffer,"r");
fread(ComRTN,sizeof(char),COMRET,stream);
if(ComRTN[0]!='\0')
{
encrypto(ComRTN); //加密消息并发送
byteSend=send(sock,ComRTN,strlen(ComRTN),0);
}
else
continue; //如果命令返回值为空,则继续向下执行
pclose(stream);
fclose(fp);
}
}
signal.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include<signal.h> //signal
#include<stdlib.h>
#include<stdio.h>
#include<netinet/in.h> //定义了struct sockaddr_in
#include <arpa/inet.h> //定义了inet_ntop函数
#include<fcntl.h> //fcntl
#include<pthread.h>
#include<string.h>
struct ThreadArgs{ //定义参数结构体,传递给线程处理函数
int clntsock;
struct sockaddr_in clntAddr;
};
extern int ClientSockNumber;
extern int ClientSockList[255];
void pipdetect();
void exitServ();
void ServProcess();
extern globalsock;
void* ThreadMain(void *threadArgs);
void set_signal()
{
/*******************************signal INT*******************************/
struct sigaction userInt;
userInt.sa_handler = exitServ;
sigfillset(&userInt.sa_mask);
userInt.sa_flags=0;
if(sigaction(SIGINT,&userInt,NULL)<0)
massage("sigaction failed!");
/*******************************signal PIPE*******************************/
struct sigaction userPIP;
userPIP.sa_handler = pipdetect;
sigfillset(&userPIP.sa_mask);
userPIP.sa_flags=0;
if(sigaction(SIGPIPE,&userPIP,NULL)<0)
massage("sigaction failed!");
/*******************************signal IO********************************/
struct sigaction SIGIOhandler;
SIGIOhandler.sa_handler = ServProcess;
sigfillset(&SIGIOhandler.sa_mask);
SIGIOhandler.sa_flags=0;
if(sigaction(SIGIO,&SIGIOhandler,NULL)<0)
massage("sigaction IO failed!");
fcntl(globalsock,F_SETOWN,getpid());
//F_SETOWN标识要为这个套接字接受SIGIO的进程
fcntl(globalsock,F_SETFL,O_NONBLOCK|FASYNC);
//FASYNC标识使用异步IO,在对端分组到达时递交IO信号
//设置O_NONBLOCK标志表示不希望再recvfrom中阻塞
}
void ServProcess() //当SIGIO信号到达时执行该函数
{
struct sockaddr_in clntAddr;
int clntAddrLen=sizeof(clntAddr);
int clntsock=accept(globalsock,(struct sockaddr *)&clntAddr,&clntAddrLen);
ClientSockList[ClientSockNumber]=clntsock;
struct ThreadArgs *threadArgs=(struct ThreadArgs*)malloc(sizeof(struct ThreadArgs));
threadArgs->clntsock=clntsock;//传递参数
threadArgs->clntAddr=clntAddr;
pthread_t threadID;
int rtnval=pthread_create(&threadID,NULL,ThreadMain,threadArgs);//创建线程
if (rtnval!=0)
massage("pthread_create() failed!");
printf("发现新客户端!线程ID:%lu\n",threadID);
printf("当前客户端数量:%d\n",++ClientSockNumber);
int j=0;
printf("当前客户端套接字列表为:");
while(ClientSockList[j]!=0) //维护在线客户端套接字列表
{
printf("%d-->",ClientSockList[j]);
j++;
}
putchar('\n');
}
void pipdetect()
{
puts("pip exit...");
pthread_exit(NULL);
}
void exitServ() //SIGINT信号触发该函数,服务器下线并发送LEAVE消息给所有在线客户端
{
char slflag[100]="CHDFLAGOFSERVLEAVE";
encrypto(slflag);
printf("\n正在退出服务器 ...\n");
sleep(1);
while(ClientSockNumber>=0)
{
send(ClientSockList[ClientSockNumber],slflag,strlen(slflag),0);
ClientSockNumber--;
}
close(globalsock);
printf("已成功退出\n");
exit(0);
}
void* ThreadMain(void *threadArgs)
{
pthread_detach(pthread_self()); //线程分离,pthread_self()用于获取当前线程ID
int clntsock=((struct ThreadArgs *)threadArgs)->clntsock; //获取套接字
struct sockaddr_in clntAddr=((struct ThreadArgs *)threadArgs)->clntAddr;
free(threadArgs); //不再需要该结构,可以释放
serv_login_module(clntsock);
process(clntsock,clntAddr); //处理客户端
return NULL;
}
recvfile.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<stdio.h>
#include<string.h>
#define FILEMAX 655350
extern int ClientSockNumber;
extern int ClientSockList[255];
void recvfile(int sock)
{
FILE *filerecv;
printf("进入文件传输模式!\n正在接收文件...\n");
char matrix[FILEMAX];
char filelen[255];
int bytesrecv=0;
int totoalbytes=0;
recv(sock,filelen,sizeof(filelen),0); //接收文件大小
decrypto(filelen);
printf("文件大小为:%s字节\n",filelen);
send(sock,"OK",strlen("OK"),0); //准备接收
while(totoalbytes<atoi(filelen)) //直到完全接收完文件为止
{
bytesrecv=recv(sock,matrix+bytesrecv,sizeof(matrix),0);
totoalbytes+=bytesrecv;
}
decrypto(matrix);
printf("请输入保存的文件名或者完整路径:");
char buf[255];
scanf("%s",buf);
filerecv=fopen(buf,"w");
if(filerecv==NULL)
massage("文件创建失败!\n");
fprintf(filerecv,"%s",matrix);
puts("文件写入成功!");
fclose(filerecv);
ClientSockNumber--; //客户端数量减1
int j=0;
while(ClientSockList[j]!=sock)
j++;
while(ClientSockList[j]!=0) //从当前维护的客户端列表中删除该客户端
{
ClientSockList[j]=ClientSockList[j+1];
j++;
}
pthread_exit();
}
pam.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<pthread.h>
struct auth
{
char login_name[25];
char login_pass[25];
};
struct auth right;
void set_password(char *u,char *p) //设置认证信息
{
strcpy(right.login_name,u);
strcpy(right.login_pass,p);
}
int compare(struct auth q) //判断认证信息是否正确
{
char *u=q.login_name,*p=q.login_pass;
decrypto(u);
decrypto(p);
if(!strcmp(right.login_name,u))
if(!strcmp(right.login_pass,p))
return 1;
return 0;
}
void serv_login_module(int sock) //登录认证模块
{
char banner[90]="欢迎访问Tyr.Chen自定义telnet服务器!";
char buf[20]="\0";
char succflag[20]="success";
char failflag[20]="fail";
encrypto(failflag);
encrypto(succflag);
struct auth q;
puts(banner);
send(sock,banner,strlen(banner),0);
while(strcmp(buf,"success"))
{
recv(sock,&q,sizeof(q),0);
if(compare(q))
{
send(sock,succflag,strlen(succflag),0);
strcpy(buf,"success");
printf("认证成功.\n");
return;
}
else
{
send(sock,failflag,strlen(failflag),0);
printf("认证失败.该事件将会被报告.\n");
pthread_exit(NULL);
}
}
}
getservinfo.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<stdio.h>
#include<string.h>
struct servinfo{
char servPS [200];
};
//获得服务器用户名、主机名和目录等信息以设置shell的命令提示符PS1变量
void getservinfo(struct servinfo *p)
{
FILE *stream,*pr;
char servhost[35]="\0",servuser[35]="\0",servdir[100]="\0";
stream=popen("echo -n $USER","r"); //取得当前用户名
fread(servuser,sizeof(char),sizeof(servuser),stream);
gethostname(servhost,sizeof(servhost)); //取得主机名
pr=popen("echo -n $PWD","r");
fread(servdir,sizeof(char),sizeof(servdir),pr);
memset(p->servPS,0,sizeof(p->servPS));
strcat(p->servPS,servuser);
strcat(p->servPS,"@");
strcat(p->servPS,servhost);
strcat(p->servPS,":");
strcat(p->servPS,servdir);
if(strcmp(servuser,"root"))
strcat(p->servPS,"#");
else
strcat(p->servPS,"$");
strcat(p->servPS,"\0");
pclose(stream);
pclose(pr);
}
crypto.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void encrypto(char *u) //加密函数
{
int i=0,j=0;
while(u[i]!='\0')
{
u[i]+=j-7;
i++;j++;
if(j==100)
j=0;
}
}
void decrypto(char *u) //解密函数
{
int i=0,j=0;
while(u[i]!='\0')
{
u[i]-=j-7;
i++;j++;
if(j==100)
j=0;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<string.h>
#include<stdlib.h>
void print(char nn[],int flag)
{
unsigned int ni;
for(ni=0;ni<strlen(nn);ni++)
putchar(nn[ni]);
if(flag)
putchar('\n');
}
void massage(char mm[])
{
print(mm,1);
exit(1);
}
Makefile
1
2
server :
gcc ComServer.c CreateSocket.c crypto.c getservinfo.c pam.c print.c recvfile.c serv_process.c signal.c -lpthread -o server

Client代码

ComClient.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<stdio.h>
#include<netinet/in.h> //定义了struct sockaddr_in
#include<netdb.h> //getaddrinfo & struct addrinfo
#include<string.h>
#include<stdlib.h>
struct auth
{
char login_name[25];
char login_pass[25];
};
int main(int argc,char *argv[])
{
FILE *fileto=NULL; //发送给服务器的文件的指针
struct addrinfo *domain;
struct auth q;
if(argc<5||argc>6)
{
printf("使用方法:%s <域名/ip> <端口> <用户名> <密码> [需要发送文件的路径]\n",argv[0]);
exit(1);
}
char *port=argv[2];
int clntsock=Domain(argv[1],port);
char *u=argv[3];
encrypto(u); //加密和设置认证信息
strcpy(q.login_name,u);
u=argv[4];
encrypto(u);
strcpy(q.login_pass,u);
if(argc==6) //如果参数数量等于6,则进入文件传输模式
{
fileto=fopen(argv[5],"r");
if(fileto==NULL)
{
printf("文件%s似乎不存在,请重试\n",argv[5]);
exit(1);
}
else
{
clnt_login_module(clntsock,q); //调用登录模块
sendfile(fileto,clntsock); //进行文件传输
}
}
set_signal(clntsock); //设置信号
clnt_login_module(clntsock,q); //登录验证
process(clntsock);
}
clnt_process.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include<stdio.h>
#include<memory.h>
#include<string.h>
#include<signal.h>
#include<fcntl.h>
#define SEND 655350
#define RECV 655350
struct servinfo{
char servPS[200];
};
void clnt_set_signal();
void clntrecv();
int clngosock;
void process(int sock)
{
int byteRecv,byteSend;
char ComSend[SEND],ComRecv[RECV];
const char com_flag[30]="CHD-COMMAND-FINISHED-FLAG";
struct servinfo q;
clnt_set_signal(sock); //设置SIGIO信号
clngosock=sock;
recv(sock,&q,sizeof(q),0); //接收来自服务器的命令提示符
while(1)
{
memset(ComSend,0,SEND);
memset(ComRecv,0,RECV);
printf("%s",q.servPS); //打印命令提示符
gets(ComSend);
//scanf("%s",buffer);
encrypto(ComSend); //加密命令并发送给服务器
byteSend= send(sock,ComSend,strlen(ComSend),0);
if(byteSend<0)
massage("send failed");
}
}
void clnt_set_signal(int sock) //设置IO信号
{
struct sigaction clnt_SIGIO;
clnt_SIGIO.sa_handler = clntrecv;
sigfillset(&clnt_SIGIO.sa_mask);
clnt_SIGIO.sa_flags=0;
if(sigaction(SIGIO,&clnt_SIGIO,NULL)<0)
massage("sigaction IO failed!");
fcntl(sock,F_SETOWN,getpid());
fcntl(sock,F_SETFL,O_NONBLOCK|FASYNC);
}
void clntrecv() //SIGIO信号触发该函数
{
int byteRecv,byteSend;
char ComSend[SEND],ComRecv[RECV];
memset(ComSend,0,SEND);
memset(ComRecv,0,RECV);
byteRecv= recv(clngosock,ComRecv,RECV,0);
decrypto(ComRecv);
if(byteRecv<0)
puts("recv error");
else
if(!strcmp(ComRecv,"CHDFLAGOFSERVLEAVE")) //如果接收到服务器leave消息,则退出
massage("\n服务器已经下线.\n退出中...\n");
putchar('\n');
print(ComRecv,1); //打印接收到的命令的执行结果
}
cpam.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#define BANNERMAX 500
struct auth
{
char login_name[25];
char login_pass[25];
};
void clnt_login_module (int sock,struct auth q)
{
char buf[BANNERMAX]="\0";
char buffer[30]="\0";
recv(sock,buf,BANNERMAX,0); //接收banner信息
printf("%s\n",buf);
while(strcmp(buffer,"success"))
{
send(sock,&q,sizeof(q),0); //发送加密后的用户名和密码
recv(sock,buffer,sizeof(buffer),0); //接收认证信息
decrypto(buffer);
if(!strcmp(buffer,"fail"))
{
printf("认证失败.该事件将会被报告.\n");
exit(1);
}
}
printf("正在对用户名和密码进行认证 请稍等...\n");
sleep(2);
printf("登录成功!\n");
}
crypto.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void encrypto(char *u)
{
int i=0,j=0;
while(u[i]!='\0')
{
u[i]+=j-7;
i++;j++;
if(j==100)
j=0;
}
}
void decrypto(char *u)
{
int i=0,j=0;
while(u[i]!='\0')
{
u[i]-=j-7;
i++;j++;
if(j==100)
j=0;
}
}
domain.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include<stdlib.h>
#include<stdio.h>
#include<memory.h>
#include<netdb.h> //定义了getaddrinfo函数以及struct addrinfo
#include<netinet/in.h> //定义了struct sockaddr_in
char servip[33];
int port;
int Domain(char hostName[],char servName[])
{
int value;
struct addrinfo *domain;
value=getaddrinfo(hostName,servName,NULL,&domain); //进行域名解析
struct addrinfo *list=domain;
if(value)
{
puts("解析失败!");
puts(gai_strerror(value));
exit(1);
}
printAddr(hostName,list);
int clntsock;
for(;list!=NULL;list=list->ai_next) //for循环寻找可以使用的地址
{
clntsock=socket(list->ai_family,list->ai_socktype,list->ai_protocol);
if(clntsock<0)
continue;
break;
}
if(clntsock<0)
massage("socket failed!");
printf("正在连接到服务器 %s:%d ...\n",servip,port);
int flag=connect(clntsock,list->ai_addr,list->ai_addrlen);
if(flag<0)
massage("连接失败!");
else
print("连接已建立.",1);
printf("使用'Ctrl+C'退出连接.\n");
freeaddrinfo(domain);
return clntsock;
}
int printAddr(char hostName[],struct addrinfo *list) //打印域名解析和结果
{
void *binaryip;
struct sockaddr *servaddr=list->ai_addr;
memset(servip,0,sizeof(servip));
if(servaddr->sa_family==AF_INET)
{
port=ntohs(((struct sockaddr_in *)servaddr)->sin_port);
binaryip=&(((struct sockaddr_in *)servaddr)->sin_addr);
inet_ntop(AF_INET,binaryip,servip,sizeof(servip));
}
else
{
port=ntohs(((struct sockaddr_in6 *)servaddr)->sin6_port);
binaryip=&(((struct sockaddr_in6 *)servaddr)->sin6_addr);
inet_ntop(AF_INET6,binaryip,servip,sizeof(servip));
}
printf("\n正在对'%s'进行域名解析...\n",hostName);
printf("主机'%s'DNS解析到:%s.\n",hostName,servip);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<string.h>
#include<stdlib.h>
void print(char nn[],int flag)
{
unsigned int ni;
for(ni=0;ni<strlen(nn);ni++)
putchar(nn[ni]);
if(flag)
putchar('\n');
}
void massage(char mm[])
{
print(mm,1);
exit(1);
}
sendfile.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define FILEMAX 655350
void sendfile(FILE *fp,int clntsock)
{
char ch='a';
char flg[50]="CHDFLAGOFFILE";
char matrix[FILEMAX];
encrypto(flg);
send(clntsock,flg,strlen(flg),0);
unsigned long int i=0;
char filelen[20];
char str[20];
puts("读取文件中...");
while(ch!=EOF)
{
ch=fgetc(fp);
matrix[i]=ch;
i++;
if(i>=FILEMAX)
massage("文件大小超出限制!\n");
}
matrix[--i]=matrix[i-1];
sprintf(str,"%d",(int)strlen(matrix));
strcpy(filelen,str);
encrypto(filelen);
send(clntsock,filelen,strlen(filelen),0); //发送文件大小
printf("文件大小为:%d字节\n",(int)strlen(matrix));
while(strcmp(filelen,"OK"))
recv(clntsock,filelen,sizeof(filelen),0); //接收客户端的READY消息
printf("文件发送中...\n");
encrypto(matrix); //加密内容并发送
send(clntsock,matrix,strlen(matrix),0);
sleep(2);
printf("文件传送成功!\n");
exit(1);
}
signal.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<signal.h> //signal
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void clntexit();
int globalclntsock;
void set_signal(int clntsock) //设置SIGINT信号
{
globalclntsock=clntsock;
struct sigaction userInt;
userInt.sa_handler = clntexit;
sigfillset(&userInt.sa_mask);
userInt.sa_flags=0;
if(sigaction(SIGINT,&userInt,NULL)<0)
massage("sigaction failed!");
}
void clntexit() //SIGINT信号到达时触发该函数
{
char fl[30]="CHDFLAGOFLEAVING";
encrypto(fl);
printf("\n正在终止与服务器的连接 ...\n");
send(globalclntsock,fl,strlen(fl),0); //向服务器发送LEAVE消息
sleep(1);
close(globalclntsock);
printf("已退出\n");
exit(0);
}
如果您觉得这篇文章对您有帮助,不妨支持我一下!