Linux平台C语言Socket编程练习之线程专用数据TSD实现

0x00 要求

采用多线程并发服务器技术,服务器可以同时接受多个客户的请求。具体要求如下:

服务端

1
2
3
4
5
接收并显示与之连接的客户端的名称;
接收客户端发来的字符串,显示出来,并对字符串做反转处理,最后将处理后的字符串发回给客户;
在每个用户退出时要显示该用户输入的所有信息。

客户端

1
2
3
4
5
6
7
根据客户输入的服务器IP地址,向服务器发起建立连接的请求;
接收客户输入的客户端名称,并把该客户端名称发给服务器;
接收客户输入的字符串,将字符串发送给服务器;
接收服务器发回的反转处理后的字符串并显示。继续接受客户输入的字符串,直到用户输入quit时退出。

0x01 代码

服务端

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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#define PORT 1234
#define BACKLOG 5
#define MAXDATASIZE 100
void process_cli(int connfd,struct sockaddr_in client,char cli_input[]);
void* function(void* arg);
struct ARG
{
int connfd;
char cli_input[1000];
struct sockaddr_in client;
};
int main()
{
int listenfd;
int connfd;
pthread_t tid;
socklen_t client_len;
struct ARG *arg;
struct sockaddr_in server;
struct sockaddr_in client;
if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
perror("socket() failed.");
exit(1);
}
int opt=SO_REUSEADDR;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(PORT);
server.sin_addr.s_addr=htonl(INADDR_ANY);
if(bind(listenfd,(struct sockaddr *)&server,sizeof(server))==-1)
{
perror("bind() failed.");
exit(1);
}
if(listen(listenfd,BACKLOG)==-1)
{
perror("listen() failed.");
exit(1);
}
client_len=sizeof(client);
while(1)
{
if((connfd=accept(listenfd,(struct sockaddr *)&client,&client_len))==-1)
{
perror("accept() failed.");
printf("runed here!\n");
exit(1);
}
arg=(struct ARG *)malloc(sizeof(struct ARG));
arg->connfd=connfd;
memcpy((void *)&arg->client,&client,sizeof(client));
if(pthread_create(&tid,NULL,function,(void *)arg))
{
perror("pthread_create() failed.");
exit(1);
}
}
close(listenfd);
return 0;
}
void process_cli(int connfd,struct sockaddr_in client,char cli_input[])
{
ssize_t send_num;
ssize_t recv_num;
char send_buf[MAXDATASIZE];
char recv_buf[MAXDATASIZE];
char client_name[MAXDATASIZE];
char wel_msg[]="[!] Welcome,you can input 'quit' to exit :) ";
printf("[!] You got a connection from client IP: <%s> PORT: <%d> \n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
if((send(connfd,wel_msg,strlen(wel_msg),0))==-1)
{
perror("send welcome messages fail.");
exit(1);
}
if((recv_num=recv(connfd,client_name,MAXDATASIZE,0))==-1)
{
perror("recv() failed.");
close(connfd);
}
if(recv_num==0)
{
printf("[!] Client disconnected.\n");
close(connfd);
}
client_name[recv_num-1]='\0';
printf("[*] Client name: <%s> \n",client_name);
while(1)
{
if((recv_num=recv(connfd,recv_buf,MAXDATASIZE,0))==-1)
{
perror("recv() error.");
exit(1);
}
recv_buf[recv_num]='\0';
printf("[*] Received string: '%s' from client: <%s> \n ",recv_buf,client_name);
int cur_save_len=strlen(cli_input);
while(recv_num--)
{
cli_input[cur_save_len+recv_num]=recv_buf[recv_num];
}
size_t len=strlen(recv_buf);
for(int i=0; i<(len/2); ++i)
{
char tmp=recv_buf[i];
recv_buf[i]=recv_buf[len-1-i];
recv_buf[len-1-i]=tmp;
}
strcpy(send_buf,recv_buf);
printf("[>] Send reverse string: '%s' to client: <%s> \n",send_buf,client_name);
if((send_num=send(connfd,send_buf,MAXDATASIZE,0))==-1)
{
perror("send() error.");
exit(1);
}
if(!strcmp(send_buf,"tiuq"))
{
printf("[!] Received a total of string: '%s' from client: <%s> and the client have disconnected! \n",cli_input,client_name);
break;
}
}
close(connfd);
}
void* function(void* arg)
{
struct ARG *info;
info=(struct ARG *)arg;
process_cli(info->connfd,info->client,info->cli_input);
free(arg);
pthread_exit(NULL);
}

客户端

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#define PORT 1234
#define MAXDATASIZE 100
int main(int argc,char *argv[])
{
int sockfd;
ssize_t send_num;
ssize_t recv_num;
char wel_msg[MAXDATASIZE];
char cli_name[MAXDATASIZE];
char recv_buf[MAXDATASIZE];
char send_buf[MAXDATASIZE];
struct hostent *he;
struct sockaddr_in server;
if(argc!=2)
{
printf("Usage:%s <IP Adress>\n",argv[0]);
exit(1);
}
if((he=gethostbyname(argv[1]))==NULL)
{
printf("gethostbyname() failed.");
exit(1);
}
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
printf("socket() failed.");
exit(1);
}
bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(PORT);
server.sin_addr=*((struct in_addr *)he->h_addr);
if(connect(sockfd,(struct sockaddr *)&server,sizeof(server))==-1)
{
printf("connect() failed.");
exit(1);
}
if ((recv(sockfd,wel_msg,MAXDATASIZE,0))==-1)
{
perror("[!] Receive welcome message fail.");
exit(1);
}
wel_msg[sizeof(wel_msg)]='\0';
printf("%s\n", wel_msg);
printf("[*] Input client name:");
scanf("%s",cli_name);
if((send_num=send(sockfd,cli_name,MAXDATASIZE,0))==-1)
{
perror("send() error.");
exit(1);
}
while(1)
{
printf("[*] Input string:");
scanf("%s",send_buf);
send_buf[strlen(send_buf)]='\0';
if((send_num=send(sockfd,send_buf,MAXDATASIZE,0))==-1)
{
perror("send() error.");
exit(1);
}
if((recv_num=recv(sockfd,recv_buf,MAXDATASIZE,0))==-1)
{
perror("recv() error.");
exit(1);
}
printf("[>] Received reverse string:%s\n",recv_buf);
if(!strcmp(recv_buf,"tiuq"))
{
break;
}
}
close(sockfd);
return 0;
}

0x02 演示

服务端

多线程TSD服务端.gif

客服端1

多线程TSD客户端1.gif

客户端2

多线程TSD客户端2.gif