linux网络编程

linux网络编程

ABOUT

其实就是一些socket编程还有就是服务端如何做到并发

所了解到的就是多进程实现并发服务器、多线程实现并发服务器、还有就是使用io复用的方式实现并发

首先简单讲述一下socket的一些东西,主要是粘代码,没什么可讲的,自己实现一遍基本就ok了

网络编程

比较简单,就是创建一个监听套接字,如果接收到客户端请求,就将监听套接字转换为连接套接字

服务段代码:

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
/*server.c*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 1234
#define BACKLOG 1
int main(void)
{
int listenfd, connectfd;
struct sockaddr_in server;
struct sockaddr_in client;
int sin_size;

if((listenfd=socket(AF_INET, SOCK_STREAM, 0))==-1)
{
perror("Create socket failed");
exit(-1);
}
int opt =1;
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(struct sockaddr))==-1)
{
perror("Bind error");
exit(-1);
}

if (listen(listenfd, BACKLOG) == -1)
{
perror("listen error");
exit(-1);
}
sin_size = sizeof(struct sockaddr_in);
while(1)
{
if ((connectfd = accept(listenfd, (struct sockaddr *)&client, &sin_size)) == -1)
{
perror("accept error");
exit(-1);
}
printf("you get a connection from %s\n", inet_ntoa(client.sin_addr));
printf("you get a connection from %d\n", ntohs(client.sin_port));
send(connectfd,"welcome to my server\n",22, 0);
close(connectfd);
} /* while */
close(listenfd);
}

客户端

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
/*client.c*/
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define PORT 1234
#define MAXDATASIZE 100
int main(int argc, char *argv[])
{
int fd, numbytes;
char buf[MAXDATASIZE];
struct hostent * he;
struct sockaddr_in server;
if (argc != 2)
{
printf("Usage: %s <IP address>\n", argv[0]);
exit(-1);
}
if ((he = gethostbyname(argv[1])) == NULL)
{
perror("gethostbyname error.");
exit(1);
}

if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Create 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(fd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)
{
perror("connect failed.");
exit(1);
}
if( ((numbytes = recv(fd, buf, MAXDATASIZE, 0)) == -1))
{
perror("recv error.");
exit(1);
}
buf[numbytes] ='\0';
printf("Server Message: %s\n",buf);
close(fd);
}

多进程实现并发服务器

其实这里就是fork一个子进程,子进程拷贝一份父进程,然后通过fork的返回值不同判断子进程胡扯父进程

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
/*server.c*/
#include <unistd.h>
#include <sys/types.h>
#include<string.h>
#include <sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 1234
#define BACKLOG 10
#define MAXDATASIZE 1000
char *revstr(char *str, size_t len);
void process_cli(int connectfd, struct sockaddr_in client);
int main(void)
{
int listenfd, connectfd;
pid_t pid;

struct sockaddr_in server, client;
int sin_size;

/* Create TCP Socket */

if((listenfd=socket(AF_INET, SOCK_STREAM, 0))==-1)
{
perror("Create 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(struct sockaddr))==-1)
{
perror("Bind error");
exit(-1);
}

if (listen(listenfd, BACKLOG) == -1) {
perror("listen error");
exit(-1);
}
sin_size = sizeof(struct sockaddr_in);

while(1) {

if((connectfd = accept(listenfd, (struct sockaddr *)&client, &sin_size)) == -1) {
perror("accept error");
exit(-1);
}
if ((pid=fork())>0) {
/* parent process */
close(connectfd);
continue;
}
else if (pid==0) {
/*child process*/
close(listenfd);
process_cli(connectfd, client);
exit(0);
}
else {
printf("fork error\n");
exit(0);
}
}/*while()*/
close(listenfd); /* close listenfd */
}
void process_cli(int connectfd, struct sockaddr_in client) {
int num;
char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];


printf("You got a connection from %s.\n", inet_ntoa(client.sin_addr));
num = recv(connectfd, cli_name, MAXDATASIZE, 0);
if (num == 0) {
close(connectfd);
printf("cllient disconnected.\n");
return;
}
cli_name[num] = '\0';
printf("Client name is %s.\n",cli_name);
while (num = recv(connectfd, recvbuf, MAXDATASIZE,0)) {
recvbuf[num] = '\0';
printf("Received client (%s) message: %s\n", cli_name, recvbuf);
int i=0;
for(i=0; i < num ; i++)
sendbuf[i] = recvbuf[num-i-1];
sendbuf[i] = '\0';
send(connectfd, revstr(recvbuf,strlen(recvbuf)), strlen(recvbuf), 0);
//send(connectfd, revstr(sendbuf,strlen(sendbuf)), strlen(sendbuf), 0);
}
close(connectfd);
}


char *revstr(char *str, size_t len)
{

char *start = str;
char *end = str + len - 1;
char ch;

if (str != NULL)
{
while (start < end)
{
ch = *start;
*start++ = *end;
*end-- = ch;
}
}
return str;
}

客户端

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
/*client.c*/
#include <unistd.h>
#include <sys/types.h>
#include<string.h>
#include <sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT 1234
#define MAXDATASIZE 100
int main(int argc, char *argv[])
{
int fd, numbytes;
char buf[MAXDATASIZE];
struct hostent * he;
struct sockaddr_in server;
if (argc != 3)
{
printf("Usage: %s <IP address>\n", argv[0]);
exit(-1);
}
if ((he = gethostbyname(argv[1])) == NULL)
{
perror("gethostbyname error.");
exit(1);
}

if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Create 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(fd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)
{
perror("connect failed.");
exit(1);
}

char msg[1024];

if (send(fd, argv[2], strlen(argv[2]), 0) == -1)
{
printf("send failed\n");
exit(1);
//return EXIT_FAILURE;
}

while (1)
{

memset(msg, 0, sizeof(1024));
printf("input text:");
fgets(msg,100,stdin);
fflush(stdin);
if (send(fd, msg, strlen(msg), 0) == -1)
{
printf("send failed\n");
exit(1);
}else{
if (recv(fd, msg, sizeof(msg), 0) > 0)
printf("messiges:%s\n", msg);
}

}

close(fd);
}

多线程实现并发服务器

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
/*server.c*/
#include <unistd.h>
#include <sys/types.h>
#include<string.h>
#include <sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#define PORT 12345
#define BACKLOG 10
#define MAXDATASIZE 1024
#define FILL_CHAR 'x'
static void revstr(char *str);
struct ARG {
int connectfd;
struct sockaddr_in client;
};
void *funtion(void *arg);
void process_cli(int connectfd, struct sockaddr_in client);
int main(void)
{
int listenfd, connectfd;
pthread_t tid;
struct ARG *arg;
struct sockaddr_in server, client;
int sin_size;

/* Create TCP Socket */

if((listenfd=socket(AF_INET, SOCK_STREAM, 0))==-1)
{
perror("Create 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(struct sockaddr))==-1)
{
perror("Bind error");
exit(-1);
}

if (listen(listenfd, BACKLOG) == -1) {
perror("listen error");
exit(-1);
}
sin_size = sizeof(struct sockaddr_in);

while(1) {

if((connectfd = accept(listenfd, (struct sockaddr *)&client, &sin_size)) == -1) {
perror("accept error");
exit(-1);
}

arg=(struct ARG*)malloc(sizeof(struct ARG));
arg->connectfd = connectfd;
memcpy((void *)&arg->client,&client,sizeof(client));
if(pthread_create(&tid,NULL,funtion,(void *)arg))
{

}

}/*while()*/
close(listenfd); /* close listenfd */
}
void process_cli(int connectfd, struct sockaddr_in client) {
int num;
char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];


printf("You got a connection from %s.\n", inet_ntoa(client.sin_addr));
num = recv(connectfd, cli_name, MAXDATASIZE, 0);
if (num == 0) {
close(connectfd);
printf("cllient disconnected.\n");
return;
}
cli_name[num] = '\0';
printf("Client name is %s.\n",cli_name);

while (num = recv(connectfd, recvbuf, 1024,0)) {
recvbuf[strlen(recvbuf)] = '\0';
if (strcmp(recvbuf, "quit") == 0)
{
send(connectfd, "bye bye!",sizeof(recvbuf), 0);
printf("client %s close.\n",cli_name);
break;
}
else{
printf("Received client (%s) message: %s\n", cli_name, recvbuf);
revstr(recvbuf);
send(connectfd, recvbuf,sizeof(recvbuf), 0);

printf("After encryption: %s\n",recvbuf);
memset(recvbuf, '\0', sizeof(1024));
}
//send(connectfd, revstr(sendbuf,strlen(sendbuf)), strlen(sendbuf), 0);
}
close(connectfd);
}

void *funtion(void *arg)
{
struct ARG *info;
info = (struct ARG *)arg;
process_cli(info->connectfd,info->client);
free(arg);
pthread_exit(NULL);
}
static void revstr(char *str)
{
int len = strlen(str);
char key[10]="2015021269";
int i=0;
int new_len;
int offset;
for (new_len = len; (new_len+1) % (10) != 0; new_len++)
{
str[new_len]=FILL_CHAR;
}
//printf("new_len is:%d\n",new_len);
new_len++;
str[new_len-1]=len+'0';
str[new_len]='\0';
printf("newstr:%s.\n",str);

for (offset = 0; offset < new_len; offset += 10)
{
for (i = 0; i < 10; i++)
{
str[offset + i] = str[offset + i] + key[i] - '0';
}
}
}

客户端

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
/*client.c*/
#include <unistd.h>
#include <sys/types.h>
#include<string.h>
#include <sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT 12345
#define MAXDATASIZE 100
#define FILL_CHAR 'x'
static void decrypt(char * msg);
int main(int argc, char *argv[])
{
int fd, numbytes,decrypt_flag;
char buf[MAXDATASIZE];
struct hostent * he;
struct sockaddr_in server;
if (argc == 3)
decrypt_flag =0;
else if(argc == 4)
decrypt_flag =1;
else{
printf("Usage: %s <IP address>\n", argv[0]);
exit(-1);
}
if ((he = gethostbyname(argv[1])) == NULL)
{
perror("gethostbyname error.");
exit(1);
}

if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Create 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(fd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)
{
perror("connect failed.");
exit(1);
}

char msg[1024],decrypt_msg[1024];

if (send(fd, argv[2], strlen(argv[2]), 0) == -1)
{
printf("send failed\n");
exit(1);
//return EXIT_FAILURE;
}

while (1)
{

memset(msg, 0, sizeof(1024));
printf("input text:");
fgets(msg,sizeof(msg),stdin);
msg[strlen(msg)-1]='\0';
if (send(fd, msg, sizeof(msg), 0) == -1)
{
printf("send failed\n");
exit(1);
}
else{
if (recv(fd, msg, sizeof(msg), 0) > 0)
printf("messiges:%s\n", msg);
if(strcmp(msg,"bye bye!")==0)
break;
}

if(decrypt_flag)
{
strcpy(decrypt_msg,msg);
decrypt(decrypt_msg);
printf("decrypt msg is:%s\n",decrypt_msg);

}
memset(msg, 0, sizeof(msg));
memset(decrypt_msg, 0, sizeof(msg));

}

close(fd);
}

static void decrypt(char *msg)
{
//msg[0]='0';
char key[10]="2015021269";
int len=strlen(msg);
int offset;
int data_len=msg[len-1]-'9';
int i;
//printf("len is:%d\n",data_len);

for (offset = 0; offset < len; offset += 10)
{
for (i = 0; i < 10; i++)
{
msg[offset + i] = msg[offset + i] - key[i] + '0';
}
}
msg[data_len]='\0';

}

这里多线程当中会涉及到一些变量安全的问题,因为所有线程都是共享变量的,所以这里会有一个线程安全问题,这里使用tsd的方式来实现线程安全,下面写一下线程安全的代码

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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*server.c*/
#include <unistd.h>
#include <sys/types.h>
#include<string.h>
#include <sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#define PORT 12345
#define BACKLOG 10
#define MAXDATASIZE 1024
#define FILL_CHAR 'x'
static void revstr(char *str);
void savedata(char* recvbuf,int len,char* cli_data);
void saveendata(char* recvbuf,int len,char* cli_data);
struct ARG {
int connectfd;
struct sockaddr_in client;
};
pthread_key_t key;
pthread_once_t once = PTHREAD_ONCE_INIT;
static void destructor(void *ptr)
{
free(ptr);
}
static void creatkey_once(void)
{
pthread_key_create(&key,destructor);
}
struct ST_DATA{
int index,indexen;
};
void *funtion(void *arg);
void process_cli(int connectfd, struct sockaddr_in client);
int main(void)
{
int listenfd, connectfd;
pthread_t tid;
struct ARG *arg;
struct sockaddr_in server, client;
int sin_size;

/* Create TCP Socket */

if((listenfd=socket(AF_INET, SOCK_STREAM, 0))==-1)
{
perror("Create 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(struct sockaddr))==-1)
{
perror("Bind error");
exit(-1);
}

if (listen(listenfd, BACKLOG) == -1) {
perror("listen error");
exit(-1);
}
sin_size = sizeof(struct sockaddr_in);

while(1) {

if((connectfd = accept(listenfd, (struct sockaddr *)&client, &sin_size)) == -1) {
perror("accept error");
exit(-1);
}

arg=(struct ARG*)malloc(sizeof(struct ARG));
arg->connectfd = connectfd;
memcpy((void *)&arg->client,&client,sizeof(client));
if(pthread_create(&tid,NULL,funtion,(void *)arg))
{

}

}/*while()*/
close(listenfd); /* close listenfd */
}
void process_cli(int connectfd, struct sockaddr_in client) {
int num;
char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];
char cli_data[1000];
char cli_endata[1000];

printf("You got a connection from %s.\n", inet_ntoa(client.sin_addr));
num = recv(connectfd, cli_name, MAXDATASIZE, 0);
if (num == 0) {
close(connectfd);
printf("cllient disconnected.\n");
return;
}
cli_name[num] = '\0';
printf("Client name is %s.\n",cli_name);

while (num = recv(connectfd, recvbuf, 1024,0)) {
recvbuf[strlen(recvbuf)] = '\0';
if (strcmp(recvbuf, "quit") == 0)
{
send(connectfd, "bye bye!",sizeof(recvbuf), 0);
//printf("client %s close.\n",cli_name);
break;
}
else{
printf("Received client (%s) message: %s\n", cli_name, recvbuf);
savedata(recvbuf,strlen(recvbuf)+1,cli_data);
revstr(recvbuf);
saveendata(recvbuf,strlen(recvbuf)+1,cli_endata);
send(connectfd, recvbuf,sizeof(recvbuf), 0);
printf("After encryption: %s\n",recvbuf);
memset(recvbuf, '\0', sizeof(1024));
}
//send(connectfd, revstr(sendbuf,strlen(sendbuf)), strlen(sendbuf), 0);
}
close(connectfd);
printf("Client(%s) closed.\nUser's data:%s\nUser's en_data:%s\n",cli_name,cli_data,cli_endata);
}

void *funtion(void *arg)
{
struct ARG *info;
info = (struct ARG *)arg;
process_cli(info->connectfd,info->client);
free(arg);
pthread_exit(NULL);
}
static void revstr(char *str)
{
int len = strlen(str);
char key[10]="2015021269";
int i=0;
int new_len;
int offset;
for (new_len = len; (new_len+1) % (10) != 0; new_len++)
{
str[new_len]=FILL_CHAR;
}
//printf("new_len is:%d\n",new_len);
new_len++;
str[new_len-1]=len+'0';
str[new_len]='\0';
printf("newstr:%s.\n",str);

for (offset = 0; offset < new_len; offset += 10)
{
for (i = 0; i < 10; i++)
{
str[offset + i] = str[offset + i] + key[i] - '0';
}
}
}

void savedata(char* recvbuf,int len,char* cli_data)
{
struct ST_DATA* data;
pthread_once(&once,creatkey_once);

if((data=(struct ST_DATA *)pthread_getspecific(key))==NULL)
{
data=(struct ST_DATA *)malloc(sizeof(struct ST_DATA));
pthread_setspecific(key,data);
data->index=0;
}
int i = 0;
while(i<len - 1)
{
cli_data[data->index++]=recvbuf[i];
i++;
}
cli_data[data->index]='\0';
}

void saveendata(char* recvbuf,int len,char* cli_data)
{
struct ST_DATA* data;
pthread_once(&once,creatkey_once);

if((data=(struct ST_DATA *)pthread_getspecific(key))==NULL)
{
data=(struct ST_DATA *)malloc(sizeof(struct ST_DATA));
pthread_setspecific(key,data);
data->indexen=0;
}
int i = 0;
while(i<len - 1)
{
cli_data[data->indexen++]=recvbuf[i];
i++;
}
cli_data[data->indexen]='\0';
}