6

これは単純なクライアント サーバー チャット プログラムです。このコードは、ネットワークに接続されたコンピューターで正常に動作します。インターネットを介してコンピューター間で接続できるように変更する方法を教えてください。サーバーのパブリック IP を使用しても機能しgethostbyname()ません。

//Client.c

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

int main(void)
{
    int clientSocket; /* Socket Decriptor for Client */
    struct sockaddr_in server_addr;
    struct hostent *ptrh;

    char message[100];
    char received[100];
    int n = 0;

    clientSocket=socket(AF_INET, SOCK_STREAM, 0);

    memset((char*)&server_addr, 0, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(10000);

    /*  bind(clientSocket, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)); */

    ptrh=gethostbyname("110.172.156.2");
    memcpy(&server_addr.sin_addr,ptrh->h_addr,ptrh->h_length);

    if( -1 == (connect(clientSocket, (struct sockaddr*)&server_addr, sizeof(server_addr)))) 
    { printf("\nServer Not Ready !!\n"); exit(1); }

while(1)
{
    printf("\nUser:-");
   // memset(message, '\0', 10);

    gets(message);

    n = write(clientSocket, message, strlen(message)+1);
if( (strcmp(message,"q") == 0 ) || (strcmp(message,"Q") == 0 ))
    {
       printf("Wrong place...Socket Closed\n");
       close(clientSocket);
       break;
    }

    //printf("Write:<%u>\n", n);

    read(clientSocket, received, sizeof(received));
    if( (strcmp(received,"q") == 0 ) || (strcmp(received,"Q") == 0 ))
    {
       printf("Wrong place...Socket Closed\n");
       close(clientSocket);
       break;
    }
    else
    printf("Server:- %s\n", received);



}

return 0;
}

//Server.c

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

int main(void) 
{
int serverSocket,client_connected,len;
struct sockaddr_in client_addr,server_addr;
struct hostent *ptrh;
int n=0; 
char message[100],received[100];

serverSocket=socket(AF_INET, SOCK_STREAM, 0);

memset((char*)&server_addr,0,sizeof(server_addr));

server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(10000);

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

if(bind(serverSocket,
(struct sockaddr*)&server_addr,sizeof(server_addr)) == -1)
printf("Bind Failure\n");
else
printf("Bind Success:<%u>\n", serverSocket);




while(1)
{   
     listen(serverSocket,5);
     len=sizeof(struct sockaddr_in);

    client_connected=accept(serverSocket,
    (struct sockaddr*)&client_addr,&len);
if (-1 != client_connected)
  printf("Connection accepted:<%u>\n", client_connected);

    while(1)
    {
    n = read(client_connected, received, sizeof(received));
    if( (strcmp(received,"q") == 0 ) || (strcmp(received,"Q") == 0 ))
    {
       printf("Wrong place...Socket Closed of Client\n");
       close(client_connected);
       break;
    }
    else{
    printf("\nUser:-%s", received);}
    printf("\nServer:-");
  //  memset(message, '\0', 10);
    gets(message);             
    write(client_connected, message, sizeof(message));
    if( (strcmp(message,"q") == 0 ) || (strcmp(message,"Q") == 0 ))
    {
       printf("Wrong place...Socket Closed of Client\n");
       close(client_connected);
       break;
    }  
    }
}

close(serverSocket); printf("\nServer Socket Closed !!\n");

return 0;
}
4

3 に答える 3

7

あなたが提供した情報に基づいて、あなたが求めている質問に対する解決策を提供することは不可能だと思います. 2 台のコンピューターが同じローカル ネットワーク上にある場合にコードが機能すると述べたので、明らかにコード (はい、問題があります) は、少なくともクライアントからサーバーに接続するのに十分に機能します。

(確立されたように) コードが機能する場合、2 つのネットワーク間にルート、パス、接続がある限り、クライアントとサーバーが同じネットワーク上にあるか別のネットワーク上にあるかは問題ではありません。したがって、クライアントがサーバーに接続できない場合は、このパスが欠落しているという結論になります。ただし、パスが見つからないことは、トラブルシューティングできる問題ではありません。「'Windows ファイアウォール' がこのアプリをブロックしている」、「私の ISP (または他の人の ISP) がこのポートをブロックしている」可能性があります。 、それは「他の人の ISP とのサービス条件には、すべてのポートをブロックすることによって強制する「サーバーなし」条項が含まれている」かもしれませんし、「私の ISP は他の人の ISP と対立していて、勝てない」かもしれません。

しかし、あなたはこのコードを投稿するのに苦労し、私は (a) コードを読み、(b) 応答を書くのに苦労したので、問題についていくつかのコメントを含めることにしました。あなたのコードを参照してください。これは完全なリストではないことが保証されていることに注意してください。

Client.c で:

  • を呼び出しmemset()て、最初の引数を にキャストしていchar *ます。この関数は、最初の引数としてmemset()a を取るように定義されています。void *#include したので<string.h>、正しいプロトタイプがスコープ内にあるので、それに渡すものはすべてvoid *自動的に に変換されます。したがって、キャストは不正確で無意味です。
  • を呼び出しgethostbyname()ており、渡す文字列は IPv4 アドレスです。
  • および関数は POSIX.1-2004gethostbyname()gethostbyaddr()廃止され、POSIX.1-2008 から除外されました。これらはgetaddrinfo()(and getnameinfo()) に置き換えられます。詳細については、の System Calls/getaddrinfo() セクションを参照Beej's Guide to Network Programmingしてください。
  • POSIX.1-2004 によると、「数値アドレス文字列が渡されたときの gethostbyname() の動作は規定されていません」。このgethostbyname()関数は、実際のホスト名が渡されることを想定しています。IP アドレスにはgethostbyaddr(). (getaddrinfo()もちろん、今でも。)
  • 機能を使用していgets()ます。このgets()関数は C99 で廃止され、POSIX.1-2008 で廃止され、C11 から除外されました。これは、入力サイズを制限する方法がないため、根本的に安全ではないためです。一般的に推奨される代替手段は です。 とは異なり、関数は文字を破棄しないfgets()ことに注意してください。gets()fgets()\n

Server.c で:

  • あなたはまだ最初の引数をmemset()にキャストしていますがchar *、これはまだ不必要で間違っています。
  • あなたgets()はまだ本質的に問題のある関数を使用していますが、
  • あなたがやっているwrite(client_connected, message, sizeof(message));。サーバーからのすべての応答は、完全な 100 バイトの長さになり、応答文字列の後にガベージ バイトが書き込まれます。strlen(message)+1代わりに使用してください。

両者に:

  • メッセージはユーザーが入力した文字列ですが、クライアントがメッセージを送信するとき、端末のヌル バイトは含まれません。受信者は送信者が書いたものしか読めないため、端末のヌルバイトを受信して​​いません...受信コードは受信したものが有効な文字列であると想定しているため、これは問題です。指定されたメッセージ サイズを よりも 1 大きくして、メッセージの文字列の末尾に null が含まれていることを確認しますstrlen(message)
于 2013-08-04T06:29:08.063 に答える
0

グローバルIPだけでデバイスに接続することはできませんが、ポート、ポートフォワード、サーバーのみを開放すればソケットを作ることができます。

于 2016-11-14T19:29:51.887 に答える