2012-05-17 3 views
2

두 개의 프로그램을 연결하는 중간 코드로 다음 코드를 작성했습니다. 두 개의 다른 시스템에서 실행중인 서버 프로그램과 클라이언트 프로그램이 있습니다. 이 코드는이 두 프로그램의 중간 역할을 할 것으로 예상됩니다.C 소켓에서 다중 연결이 필요합니다.

#include <sys/socket.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 

//Connect with program on server side 
char * serv_con(char app_data[50]) 
{ 
int sock, bytes_recieved; 
char send_data[1024]; 
char *recv_data = malloc(1024); 
struct hostent *host; 
struct sockaddr_in server_addr; 
host = gethostbyname("10.47.3.249"); 
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
{ 

    perror("Socket"); 
    exit(1); 

} 
server_addr.sin_family = AF_INET;  
server_addr.sin_port = htons(3128); 
server_addr.sin_addr = *((struct in_addr *)host->h_addr); 
bzero(&(server_addr.sin_zero),8); 
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) 
{ 

    perror("Connect"); 
    exit(1); 

} 
bytes_recieved=recv(sock,recv_data,1024,0); 
recv_data[bytes_recieved] = '\0'; 
send(sock, app_data, 50, 0); 
return recv_data; 
//close(sock); 

} 


//Connect with client app 
char * cli_con(char ser_data[50]) 
{ 
int sock, connected, bytes_recieved , true = 1; 
char send_data [1024]; 
char *recv_data = malloc(1024);  
struct sockaddr_in server_addr,client_addr;  
int sin_size; 
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
{ 

    perror("Socket"); 
    exit(1); 

} 
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1) 
{ 

    perror("Setsockopt"); 
    exit(1); 

} 
server_addr.sin_family = AF_INET;   
server_addr.sin_port = htons(5000);  
server_addr.sin_addr.s_addr = INADDR_ANY; 
bzero(&(server_addr.sin_zero),8); 
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) 
{ 

    perror("Unable to bind1"); 
    exit(1); 

} 
if (listen(sock, 5) == -1) 
{ 

    perror("Listen"); 
    exit(1); 

} 
sin_size = sizeof(struct sockaddr_in); 
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size1); 
printf("\n I got a connection from (%s , %d)",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port)); 
bytes_recieved = recv(connected,recv_data,1024,0); 
recv_data[bytes_recieved] = '\0'; 
send(connected, ser_data,50, 0); 
//close(sock); 

} 


int main() 
{ 

char *ser_data, *app_data; 
int pid = fork(); 
while(1) 
{ 

    if(pid == 0) 
     app_data = serv_con(ser_data); 

    else 
     ser_data = cli_con(app_data); 

} 

} 

클라이언트 측 응용 프로그램이 실행될 때까지 정상적으로 작동합니다. 그러나 즉시 클라이언트 측 응용 프로그램이 실행되는 오류주는 코드 출구 : 나는 코드에서 확인해야 어떤 수정

Unable to bind: Address already in use 
I got a connection from (192.168.0.3 , 45691) 

이 오류를 해결하기를? 나는 리눅스에서 일하고있다. 미리 감사드립니다.

편집 : close(sock)에서 주석을 제거했으며 을 추가했습니다. 기능은 cli_con입니다. 클라이언트 측 코드는 아래와 같습니다 :

int sock, bytes_recieved; 
char send_data[1024],recv_data[1024]; 
struct hostent *host; 
struct sockaddr_in server_addr; 
host = gethostbyname("192.168.0.2"); 
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
{ 
    perror("Socket"); 
    exit(1); 
} 
server_addr.sin_family = AF_INET;  
server_addr.sin_port = htons(5555); 
server_addr.sin_addr = *((struct in_addr *)host->h_addr); 
bzero(&(server_addr.sin_zero),8); 
if (connect(sock, (struct sockaddr *)&server_addr, 
sizeof(struct sockaddr)) == -1) 
{ 
    perror("Connect"); 
    exit(1); 
} 
while(1) 
{ 
    //necessary codes 
    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) 
    { 
     close(sock); 
     goto connct; 
    } 
} 

하지만 지금 실행에, 첫 번째 프로그램이 종료 doesnot 그러나 심지어

I got a connection from (192.168.0.3 , 45691) 

를 인쇄 doesnot 그러나 다만 어떤 메시지를 인쇄하지 않고 실행에 유지합니다. 하지만 다른 한편으로는 클라이언트가 오류를 보여주는 것으로 끝납니다 :

Connect: Connection reset by peer 

이제 어떻게해야합니까?

+0

"(192.168.0.3, 45691)과의 연결이 있습니다."-이 또한 인쇄됩니까? 바인드 오류로 인해 코드가 종료되면 어떻게 가능합니까? – Jay

+0

글쎄, 나는 그것이 while 회 돌이라고 생각한다. 처음으로 연결을 얻었고 두 번째로 루프에 들어가면 바인드 오류가 표시되어 종료됩니다. 어떤 생각을해야합니까? –

답변

2

클라이언트가 연결을 끊으면 새 서버 소켓을 만들어 동일한 포트에 바인딩합니다. 서버 측 소켓이 닫히지 않으면 포트가 여전히 사용 중이므로 bind이 실패합니다.

일반적으로 소켓 프로그램의 서버 측은 많은 클라이언트의 연결을 처리 할 수 ​​있도록 accept 주위에 루프를 가지고 있습니다. 이렇게하면 bindlisten은 한 번만 호출됩니다.

while (connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size1)) { 
    printf("\n I got a connection from (%s , %d)",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port)); 
    bytes_recieved = recv(connected,recv_data,1024,0); 
    recv_data[bytes_recieved] = '\0'; 
    send(connected, ser_data,50, 0); 
    close(connected); 
} 
+0

위 코드에서 주석 처리 된'close (sock)'을 사용하여 소켓을 닫았습니다. 그래도 같은 오류가 발생합니다. 항구를 어떻게 닫을 수 있습니까? –

+0

@HarikrishnanT : close() 호출은 소켓 사용을 마친 후에 소켓을 닫습니다. 오류 메시지는 다른 사람이 소켓을 사용 중이므로 처음부터 소켓을 사용할 수 없다는 것을 알려줍니다. – Malvineous

+0

왜 새 서버 소켓을 만들겠습니까? 포트는 소켓이 닫힌 후에 OS에 의해 자동으로 해제되지만 시간이 걸릴 수 있습니다. 당신은 SO_REUSEADDR 옵션을 설정하여 여전히 사용중인 포트에서'bind'를 허용 할 수 있습니다. 그러나 보통 포트가 아닌 소켓을 재사용하기를 원합니다. – Joni

2

즉, 포트 5000에서 수신 대기 중이지만 해당 포트에서 수신 대기중인 프로그램이 이미 있습니다 (포트를 제대로 닫지 않은 프로그램의 이전 버전 일 수 있음). 포트 번호를 다른 것으로 변경하십시오 값을 입력하거나 포트에서 수신 대기하는 모든 응용 프로그램을 닫습니다.

Linux를 사용하고 있으므로 "netstat -nlp"를 루트로 사용하여 어떤 프로그램에서 어떤 포트가 열려 있는지 확인할 수 있습니다.

+0

코드에서 열린 포트를 닫으려면 어떻게해야합니까? –

2

당신을위한 하나의 포인터는 청취 소켓과 수신 전화에서 얻은 소켓을 모두 닫아야한다는 것입니다.

close(connected); 
close(sock); 

또한, 소켓은 사용의 후 OS에 의해 해제 언젠가 소요 그래서, 그것은 오류 "이미 사용중인 주소"는 실패 할 수 있습니다. 코드의 SO_REUSEADDR 부분이 제대로 실행되고 있으면 코드에서 다시 제대로 확인할 수 있습니다.

또한 주 함수 자체에서 청취 소켓 생성 코드를 추가하여 cli_con 함수에 인수로 전달할 수 있습니다. 일반적으로 따라야 할 메커니즘은 청취 소켓을 하나 만들고 클라이언트에서 다중 연결을 수락하는 것입니다.

원래 코드에서 ser_data & app_data에 대한 적절한 메모리 할당, 초기화 등이 필요합니다.

+0

위의 편집을 참조하십시오. –

+0

cli_con에도 루프를 추가 했습니까? 나는 당신의 클라이언트가 계속 while 루프에 있고 어떤 수의 연결 후에 서버가 연결을 받아들이기를 거부하기 때문에 오류가 발생했다고 생각한다. 서버 측은 accept를 받기 전과 후에 print를 추가하여 연결이되는지 확인하십시오. – Jay

관련 문제