我知道你会将其标记为重复(question1,question2,question3),但答案并不是我要的(我想其他人也是)。所以,我向套接字高手们请教:如果我关闭套接字,如何获得绑定错误(地址已在使用中)?我将描述我的问题。
引用:
是否有一种方法可以使其正常工作而不需要任何魔法(SO_REUSEADDR)?我知道我的代码有问题...
谢谢大家。
这是代码:
客户端
引用:
我有一个客户端与 服务器 通信
在服务器上,我有两个套接字:sockS(主套接字,监听)和 sockTX(客户端套接字)
如果我调用程序一次,通信很好,然后我关闭两个套接字
如果我重新启动服务器和客户端,则会出现错误,并且我必须等待 TIME_WAIT(在 Ubuntu 32位上大约3分钟)。
是否有一种方法可以使其正常工作而不需要任何魔法(SO_REUSEADDR)?我知道我的代码有问题...
谢谢大家。
这是代码:
客户端
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 5000
#define SERVER "127.0.0.1"
#define MAXLINE 128
int printMessage(char* str);
int main(){
char buff[MAXLINE+1];
struct sockaddr_in server, client;
struct hostent *host;
int sock, n;
//socklen_t len;
if((sock = socket(AF_INET,SOCK_STREAM,0)) == -1){
perror("\nErrore socket()");
return -1;
}
client.sin_family = AF_INET;
client.sin_port = htons(0); // la porta e' scelta dal sistema operativo
client.sin_addr.s_addr = htonl(INADDR_ANY);
if( bind(sock,(struct sockaddr*)&client, sizeof(client)) == -1){
perror("\nErrore bind()");
return -1;
}
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
if((host = gethostbyname(SERVER)) == NULL ){
perror("\nErrore gethostbyname()");
return -1;
}
server.sin_addr = *((struct in_addr *)host->h_addr);
if(connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0){
perror("\nErrore connect");
return -1;
}
// MESSAGGIO
sprintf(buff, "CTX\nclientTX\nserver\nCiao da client\n");
if(send(sock, buff, strlen(buff), 0) < 0) {
perror("\nErrore sendto");
return -1;
}
else {
printf("\nMessaggio inviato");
}
if((n = recv(sock, buff, MAXLINE, 0)) < 0) {
perror("\nErrore ricezione risposta");
return -1;
} else {
buff[n] = '\0';
int test = printMessage(buff);
printf("\nEsito: %s\n", (test == 1 ? "OK" : "FAIL"));
}
shutdown(sock, 2); // 2 = RD_WR
close(sock);
return 0;
}
int printMessage(char* str){
int i;
char* temp;
printf("Mittente: ");
for(i = 0; str[i] != '\n'; i++)
printf("%c", str[i]);
printf(" ");
for(i = i+1; str[i] != '\n'; i++)
printf("%c", str[i]);
printf("\nDestinatario: ");
for(i = i+1; str[i] != '\n'; i++)
printf("%c", str[i]);
temp = (char*)malloc(30 * sizeof(char));
strncpy(temp, str+i+1, 30);
printf("Messaggio: %s\n", temp);
if(strcmp(temp, "OK") == 0)
return 1;
else
return 0;
}
服务器:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 5000
#define SERVER "127.0.0.1"
#define MAXLINE 128
int printMessage(char* str);
int main() {
char buff[MAXLINE+1];
struct sockaddr_in server; //, client;
int sockS, sockTX, n;
if((sockS = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
perror("\nErrore socket()");
return -1;
}
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sockS, (struct sockaddr *)&server, sizeof(server)) == -1)
{
perror("\nErrore bind()");
return -1;
}
if(listen(sockS, 10) == -1)
{
perror("\nErrore listen()");
return -1;
}
printf("SERVER\nInizializzazione completata!\n");
if((sockTX = accept(sockS, (struct sockaddr *)NULL, NULL)) == -1)
{
perror("\nErrore accept()");
return -1;
}
printf("Socket connesso\n");
// INVIO
if((n = recv(sockTX, buff, MAXLINE, 0)) < 0) {
perror("\nErrore recv()");
return -1; // BREAK??
} else {
buff[n] = '\0';
printMessage(buff);
}
sprintf(buff, "S\nserver\nclientTX\nOK\n");
if(send(sockTX, buff, strlen(buff), 0) < 0){
perror("\nErrore send()");
return -1; // BREAK??
} else {
printf("Risposta inviata\n");
}
shutdown(sockTX, 2);
close(sockTX);
shutdown(sockS, 2);
close(sockS);
return 0;
}
int printMessage(char* str){
int i;
char* temp;
printf("Mittente: ");
for(i = 0; str[i] != '\n'; i++)
printf("%c", str[i]);
printf(" ");
for(i = i+1; str[i] != '\n'; i++)
printf("%c", str[i]);
printf("\nDestinatario: ");
for(i = i+1; str[i] != '\n'; i++)
printf("%c", str[i]);
temp = (char*)malloc(30 * sizeof(char));
strncpy(temp, str+i+1, 30);
printf("Messaggio: %s\n", temp);
if(strcmp(temp, "OK\n") == 0)
return 1;
else
return 0;
}
大家好,谢谢你们的支持
编辑1:可能的解决方案(不是很完美,但比SOCK_REUSEADDR更好)
在两个服务器套接字关闭之前,尝试添加sleep(1)。
客户端将在服务器之前关闭,并且它会正常工作。
我知道这不是很完美。
或者更好的方法是,在服务器内部关闭第一个套接字之前,您可以检查客户端是否关闭了连接(类似于这里)
SO_REUSEADDR
的一个原因是,当真的有另一个服务器使用端口时,它可能掩盖了错误。提问者没有很好地提出问题,但问题是是否有一种关闭套接字的方法可以避免TIME-WAIT状态。 - jxh