[C]Почему bind в данном случае выдаёт ошибку Address already in use?
07.11.2010, 00:52. Показов 8523. Ответов 2
Пытаюсь разобраться с темой сокетов. Есть клиент и сервер,которые связываются через STREAM сокет. Принцип такой:
Сервер ожидает входящих соединений,принимает строку от клиента,затем посылает её всем подключенным клиентам.
Поскольку рабочего примера клиента не было,я попробовал изменить имеющийся клиент(который мог только отправлять сообщение) так,чтобы он не только посылал сообщение,но и принимал ответ от сервера.
Проблема: хотя используется функция | C | 1
| setsockopt(newfd, SOL_SOCKET, SO_REUSEADDR, 1, sizeof(int)); |
|
bind выдаёт ошибку bind: Address already in use. Почему? Вот коды клиента и сервера
talker.c
| 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
121
122
123
124
125
126
127
128
129
130
131
| /*
** talker.c -- a datagram "client" demo
*/
/* -------------------------------------------------------------------------- */
#define _GNU_SOURCE
/* -------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define SERVERPORT "4950" /* the port users will be connecting to*/
#define MAXDATASIZE 100
/* get sockaddr, IPv4 or IPv6:*/
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[])
{
int sockfd;
int newfd,newfd2; /* newly accept()ed socket descriptor*/
socklen_t addrlen;
struct addrinfo hints, *servinfo, *p;
int rv;
int numbytes = 1;
char buf[MAXDATASIZE];
char remoteIP[INET6_ADDRSTRLEN];
int yes=1; /* for setsockopt() SO_REUSEADDR, below*/
if (argc != 2) {
fprintf(stderr,"usage: %s hostname \n",argv[0]);
exit(1);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
/* loop through all the results and make a socket*/
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1 ||
(newfd = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
{
perror("talker: socket");
continue;
}
/* lose the pesky "address already in use" error message*/
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
setsockopt(newfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
break;
}
if (p == NULL) {
fprintf(stderr, "talker: failed to bind socket\n");
return 2;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen))
perror("talker: sendto");
if (bind(newfd, p->ai_addr, p->ai_addrlen) < 0) {
perror("bind");
close(newfd);
}
/* listen*/
if (listen(newfd, 10) == -1) {
perror("listen");
exit(3);
}
while (numbytes) {
scanf( "%s", buf );
if ((numbytes = send(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
perror("talker: sendto");
exit(1);
}
else {
/* handle new connections*/
addrlen = sizeof p->ai_addr;
printf("talker: sent %d bytes to %s\n", numbytes, argv[1]);
newfd2 = accept(newfd, (struct sockaddr *)&p->ai_addr, &addrlen);
/* handle data from a client*/
if ((numbytes = recv(newfd2, buf, sizeof buf, 0)) <= 0) {
/* got error or connection closed by client*/
if (numbytes == 0) {
/* connection closed*/
printf("talker: socket %d hung up\n", newfd2);
} else {
perror("recv");
}
close(newfd2); /* bye!*/
} else {
printf("talker: gotmessage from %s on "
"socket %d, MSG: %s\n",
inet_ntop(p->ai_family,
get_in_addr((struct sockaddr*)&p->ai_addr),
remoteIP, INET6_ADDRSTRLEN),
newfd2,buf);
}
}
}
freeaddrinfo(servinfo);
close(sockfd);
close(newfd);
close(newfd2);
return 0;
} |
|
selectserver.c
| 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
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
| /*
** selectserver.c -- a cheezy multiperson chat server
*/
/* -------------------------------------------------------------------------- */
#define _GNU_SOURCE
/* -------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT "4950" /* port we're listening on*/
#define MAXDATASIZE 100
/* get sockaddr, IPv4 or IPv6:*/
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
fd_set master; /* master file descriptor list*/
fd_set read_fds; /* temp file descriptor list for select()*/
int fdmax; /* maximum file descriptor number*/
int listener; /* listening socket descriptor*/
int newfd; /* newly accept()ed socket descriptor*/
struct sockaddr_storage remoteaddr; /*// client address*/
socklen_t addrlen;
char buf[MAXDATASIZE]; /* buffer for client data*/
int nbytes;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1; /* for setsockopt() SO_REUSEADDR, below*/
int i, j, rv;
struct addrinfo hints, *ai, *p;
FD_ZERO(&master); /* clear the master and temp sets*/
FD_ZERO(&read_fds);
/* get us a socket and bind it*/
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "selectserver: %s\n", gai_strerror(rv));
exit(1);
}
for(p = ai; p != NULL; p = p->ai_next) {
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) {
continue;
}
/* lose the pesky "address already in use" error message*/
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}
break;
}
if (p == NULL) {/* if we got here, it means we didn't get bound*/
fprintf(stderr, "selectserver: failed to bind\n");
exit(2);
}
freeaddrinfo(ai); /* all done with this*/
/* listen*/
if (listen(listener, 10) == -1) {
perror("listen");
exit(3);
}
/* add the listener to the master set*/
FD_SET(listener, &master);
/* keep track of the biggest file descriptor*/
fdmax = listener; /* so far, it's this one*/
/* main loop*/
for(;;) {
read_fds = master; /*// copy it*/
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
/* run through the existing connections looking for data to read*/
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) { /* we got one!!*/
if (i == listener) {
/* handle new connections*/
addrlen = sizeof remoteaddr;
newfd = accept(listener,(struct sockaddr *)&remoteaddr, &addrlen);
if (newfd == -1) {
perror("accept");
} else {
FD_SET(newfd, &master); /* add to master set*/
if (newfd > fdmax) { /* keep track of the max*/
fdmax = newfd;
}
printf("selectserver: new connection from %s on "
"socket %d\n",inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN),
newfd);
}
} else {
/* handle data from a client*/
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
/* got error or connection closed by client*/
if (nbytes == 0) {
/* connection closed*/
printf("selectserver: socket %d hung up\n", i);
} else {
perror("recv");
}
close(i); /* bye!*/
FD_CLR(i, &master); /* remove from master set*/
} else {
printf("selectserver: gotmessage from %s on "
"socket %d, MSG: %s\n",
inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN),
newfd,buf);
/* we got some data from a client*/
for(j = 0; j <= fdmax; j++) {
/*// send to everyone!*/
if (FD_ISSET(j, &master)) {
/* except the listener and ourselves*/
if (j != listener && j != i) {
if (send(j, buf, nbytes, 0) == -1) {
perror("send");
}
}
}
}
}
} /* END handle data from client*/
} /* END got new incoming connection*/
} /* END looping through file descriptors*/
} /* END for(;;) */
return 0;
} |
|
В чём там проблема?
Добавлено через 7 часов 13 минут
Вроде удалось частично разобраться и исправить код. Но я всё равно не понимаю,почему работает именно так:
После отправки сообщения на сервер,ответ от сервера запаздывает на 3 сообщения,то есть при вводе в терминале клиента получим нечто подобное
| Code | 1
2
3
4
5
6
7
8
9
10
| Input message:fff
Input message:hhh
Input message:aaa
selectserver: gotmessage from (null) on socket 4, MSG: fff
Input message:sss
selectserver: gotmessage from (null) on socket 4, MSG: hhh
Input message:ggg
selectserver: gotmessage from (null) on socket 4, MSG: aaa
Input message:jjj
selectserver: gotmessage from (null) on socket 4, MSG: sss |
|
Это что,особенности работы сокетов на конкретной системе,или что-то другое?
selectserver.c
| 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
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
| /*
** selectserver.c -- a cheezy multiperson chat server
*/
/* -------------------------------------------------------------------------- */
#define _GNU_SOURCE
/* -------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT "4953" /* port we're listening on*/
#define MAXDATASIZE 100
/* get sockaddr, IPv4 or IPv6:*/
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
fd_set master; /* master file descriptor list*/
fd_set read_fds,write_fds; /* temp file descriptor list for select()*/
int fdmax; /* maximum file descriptor number*/
int listener; /* listening socket descriptor*/
int newfd; /* newly accept()ed socket descriptor*/
struct sockaddr_storage remoteaddr; /*// client address*/
socklen_t addrlen;
char buf[MAXDATASIZE]; /* buffer for client data*/
int nbytes;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1; /* for setsockopt() SO_REUSEADDR, below*/
int i, j, rv;
struct addrinfo hints, *ai, *p;
FD_ZERO(&master); /* clear the master and temp sets*/
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
/* get us a socket and bind it*/
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "selectserver: %s\n", gai_strerror(rv));
exit(1);
}
for(p = ai; p != NULL; p = p->ai_next) {
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) {
continue;
}
/* lose the pesky "address already in use" error message*/
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}
break;
}
if (p == NULL) {/* if we got here, it means we didn't get bound*/
fprintf(stderr, "selectserver: failed to bind\n");
exit(2);
}
freeaddrinfo(ai); /* all done with this*/
/* listen*/
if (listen(listener, 10) == -1) {
perror("listen");
exit(3);
}
/* add the listener to the master set*/
FD_SET(listener, &master);
/* keep track of the biggest file descriptor*/
fdmax = listener; /* so far, it's this one*/
/* main loop*/
for(;;) {
read_fds = master; /*// copy it*/
write_fds = master; /*// copy it*/
if (select(fdmax+1, &read_fds, &write_fds, NULL, NULL) == -1) {
perror("select");
exit(4);
}
/* run through the existing connections looking for data to read*/
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) { /* we got one!!*/
if (i == listener) {
/* handle new connections*/
addrlen = sizeof remoteaddr;
newfd = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);
if (newfd == -1) {
perror("accept");
} else {
FD_SET(newfd, &master); /* add to master set*/
if (newfd > fdmax) { /* keep track of the max*/
fdmax = newfd;
}
printf("selectserver: new connection from %s on "
"socket %d\n",inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN),
newfd);
}
} else {
/* handle data from a client*/
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
/* got error or connection closed by client*/
if (nbytes == 0) {
/* connection closed*/
printf("selectserver: socket %d hung up\n", i);
} else {
perror("recv");
}
close(i); /* bye!*/
FD_CLR(i, &master); /* remove from master set*/
} else {
printf("selectserver: gotmessage from %s on "
"socket %d, MSG: %s\n",
inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN),
newfd,buf);
/* we got some data from a client*/
for(j = 0; j <= fdmax; j++) {
/*// send to everyone!*/
if (FD_ISSET(j, &write_fds)) {
/* except the listener and ourselves*/
if (j != listener && j != i) {
if (send(j, buf, sizeof buf, 0) == -1) {
perror("send");
}
}
}
}
}
} /* END handle data from client*/
} /* END got new incoming connection*/
} /* END looping through file descriptors*/
} /* END for(;;) */
return 0;
} |
|
talker.c
| 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
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
| /*
** talker.c -- a datagram "client" demo
*/
/* -------------------------------------------------------------------------- */
#define _GNU_SOURCE
/* -------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define SERVERPORT "4953" /* the port users will be connecting to*/
#define MAXDATASIZE 100
/* get sockaddr, IPv4 or IPv6:*/
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[])
{
fd_set master; /* master file descriptor list*/
fd_set read_fds,write_fds; /* temp file descriptor list for select()*/
int fdmax; /* maximum file descriptor number*/
int sockfd,sockfd1; /* listening socket descriptor*/
struct sockaddr_storage remoteaddr; /*// client address*/
struct addrinfo hints, *servinfo, *p;
int rv,i;
int numbytes = 1;
char buf[MAXDATASIZE];
char remoteIP[INET6_ADDRSTRLEN];
int yes=1; /* for setsockopt() SO_REUSEADDR, below*/
if (argc != 2) {
fprintf(stderr,"usage: %s hostname \n",argv[0]);
exit(1);
}
FD_ZERO(&master); /* clear the master and temp sets*/
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
/* loop through all the results and make a socket*/
for(p = servinfo;p != NULL;p = p->ai_next) {
if ((sockfd = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1 ||
(sockfd1 = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
{
perror("talker: socket");
continue;
}
/* lose the pesky "address already in use" error message*/
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1 ||
setsockopt(sockfd1,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt:sockfd");
exit(1);
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1 ||
connect(sockfd1, p->ai_addr, p->ai_addrlen) == -1 ) {
close(sockfd);
close(sockfd1);
perror("client: connect");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "talker: failed to bind socket\n");
return 2;
}
/* add the listener to the master set*/
FD_SET(sockfd, &master);
FD_SET(sockfd1, &master);
/* keep track of the biggest file descriptor*/
sockfd1 > sockfd ? (fdmax = sockfd1):(fdmax = sockfd);
while (numbytes) {
read_fds = master; /*// copy it*/
write_fds = master;
if (select(fdmax+1, &read_fds,&write_fds, NULL, NULL) == -1) {
perror("select");
exit(4);
}
/* run through the existing connections looking for data to read*/
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &write_fds)) { /* we got one!!*/
if (i == sockfd) {
printf("Input message:");
scanf( "%s", buf );
if ((numbytes = send(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
perror("talker: sendto");
exit(1);
}
memset(buf,'\0',sizeof buf);
}
}
if (FD_ISSET(i, &read_fds)) {
if ((numbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
if (numbytes == 0) {
printf("selectserver: socket %d hung up\n", i);
} else {
perror("recv");
}
close(i);
FD_CLR(i, &master);
} else {
printf("selectserver: gotmessage from %s on "
"socket %d, MSG: %s\n",
inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN),
sockfd1,buf);
memset(buf,'\0',sizeof buf);
}
}
}
}
freeaddrinfo(servinfo);
close(sockfd);
close(sockfd1);
return 0;
} |
|
Не по теме:
Форматирование кода немного неудачное,это потому,что там табы вместо пробелов :(
0
|