网络编程之socket实战

网络编程之socket实战,实现了多进程并发处理socket以及点对点的聊天程序。


多进程并发处理socket连接

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#define ERR_EXIT(m) \
do{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
void do_service(int conn) {
char recvbuf[1024];
while (1) {
memset(recvbuf, 0, sizeof(recvbuf));
int ret = read(conn, recvbuf, sizeof(recvbuf));
if (ret == 0) {
printf("client close\n");
break;
} else if(ret == -1) {
ERR_EXIT("read");
}
fputs(recvbuf, stdout);
write(conn, recvbuf, sizeof(recvbuf));
}
}
int main() {
int listenfd;
if ((listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
ERR_EXIT("socket");
}
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(5188);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
int on = 1;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
ERR_EXIT("setsockopt");
}
if (bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
ERR_EXIT("bind");
}
if (listen(listenfd, SOMAXCONN) < 0) {
ERR_EXIT("listen");
}
struct sockaddr_in peeraddr;
socklen_t peerlen = sizeof(peeraddr);
int conn;
pid_t pid;
while (1) {
if ((conn = accept(listenfd, (struct sockaddr *)&peeraddr, &peerlen)) < 0) {
ERR_EXIT("accept");
}
printf("ip=%s, port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
if ((pid = fork()) < 0) {
ERR_EXIT("fork");
} else if (pid == 0) {
close(listenfd);
do_service(conn);
close(conn);
exit(EXIT_SUCCESS);
} else {
close(conn);
}
}
close(listenfd);
return 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
/*p2psvr.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <signal.h>
void handler(int arg) {
printf("recv singal %d\n", arg);
exit(EXIT_SUCCESS);
}
#define ERR_EXIT(m) \
do{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
int main() {
int listenfd;
if ((listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
ERR_EXIT("socket");
}
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(5188);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
// serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
// inet_aton("127.0.0.1", &serveraddr.sin_addr.s_addr);
int on = 1;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
ERR_EXIT("setsockopt");
}
if (bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
ERR_EXIT("bind");
}
if (listen(listenfd, SOMAXCONN) < 0) {
ERR_EXIT("listen");
}
struct sockaddr_in peeraddr;
socklen_t peerlen = sizeof(peeraddr);
int conn;
if ((conn = accept(listenfd, (struct sockaddr *)&peeraddr, &peerlen)) < 0) {
ERR_EXIT("accept");
}
printf("ip=%s, port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
pid_t pid;
if ((pid = fork()) < 0) {
ERR_EXIT("fork");
} else if(pid == 0) { // 子进程
signal(SIGUSR1, handler);
char sendbuf[1024] = {0};
while (fgets(sendbuf, sizeof(sendbuf), stdin) != 0) {
if (write(conn, sendbuf, sizeof(sendbuf)) < 0) {
ERR_EXIT("write");
}
memset(sendbuf, 0, sizeof(sendbuf));
}
printf("child close\n");
close(conn);
} else { // 父进程
char recvbuf[1024] = {0};
while (1) {
int ret;
if ((ret = read(conn, recvbuf, sizeof(recvbuf))) < 0) {
ERR_EXIT("read");
} else if (ret == 0) {
printf("client close\n");
break;
}
fputs(recvbuf, stdout);
memset(recvbuf, 0, sizeof(recvbuf));
}
printf("parent close\n");
kill(pid, SIGUSR1);
sleep(1);
close(conn);
}
close(listenfd);
return 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
/*p2pcli.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <signal.h>
#define ERR_EXIT(m) \
do{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
void handler(int arg) {
printf("recv singal %d\n", arg);
exit(EXIT_SUCCESS);
}
int main() {
int sock;
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
ERR_EXIT("socket");
}
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(5188);
serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if (connect(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
ERR_EXIT("connect");
}
pid_t pid;
if ((pid = fork()) < 0) {
ERR_EXIT("fork");
} else if (pid == 0) { // 子进程
signal(SIGUSR1, handler);
char sendbuf[1024] = {0};
while (fgets(sendbuf, sizeof(sendbuf), stdin) != 0) {
if (write(sock, sendbuf, sizeof(sendbuf)) < 0) {
ERR_EXIT("write");
}
memset(sendbuf, 0, sizeof(sendbuf));
}
printf("child close\n");
close(sock);
} else { // 父进程
char recvbuf[1024] = {0};
while (1) {
int ret;
if ((ret = read(sock, recvbuf, sizeof(recvbuf))) < 0) {
ERR_EXIT("read");
} else if (ret == 0) {
printf("server close\n");
break;
}
fputs(recvbuf, stdout);
memset(recvbuf, 0, sizeof(recvbuf));
}
printf("parent close\n");
kill(pid, SIGUSR1);
close(sock);
}
return 0;
}