1

私は少し奇妙な問題を抱えています。CクライアントとJavaサーバー間のインターフェースを作成しようとしています。この目的のために、Javaでゲートウェイを作成しました(RMIを使用してサーバーと通信します)。ほとんどすべてが機能していますが、ゲートウェイからCクライアントにいくつかの整数を返そうとしています。コードは次のとおりです。

Javaゲートウェイ:

import java.net.Socket;
import java.net.ServerSocket;
import java.net.MalformedURLException;
import java.io.BufferedReader;
import java.net.InetSocketAddress;
import java.io.InputStreamReader;
import java.io.DataOutputStream;
import java.lang.System;

public class hotelgw{

  public static final int PORT = 4242;
  public static final int BACKLOG = 5;
  public static final int MAX_ARGS = 5;

  public hotelgw(){
    InetSocketAddress address;
    ServerSocket socket = null;
    try{
      address = new InetSocketAddress(PORT);
      socket = new ServerSocket(PORT,BACKLOG);
    }catch (Exception e){
      System.out.println("Error: "+e);
      System.exit(1);
    }

    while(true){

      Socket newsock = null;
      try{
       newsock =  socket.accept();
      }catch (Exception e){
        System.out.println("Error: "+e);
        System.exit(1);
      }

      BufferedReader in = null;
      DataOutputStream out = null;

      try{
        in = new BufferedReader(new InputStreamReader(newsock.getInputStream()));
        out = new DataOutputStream(newsock.getOutputStream());
      }catch (Exception e){
        System.out.println("Error: "+e);
        System.exit(1);
      }


      String[] init_args = new String[MAX_ARGS];
      int i = 0;
      String c;

      try{
        while(!(c = in.readLine()).equals("end")){
          System.out.printf("%s",c);
          init_args[i] = c;
          i++;
        }
      }catch (Exception e){
        System.out.println("Error: "+e);
        System.exit(1);
      }

      for(int j=0;j<init_args.length;j++){
        System.out.printf("init_args[%d] = %s\n", j, init_args[j]);
      }

      int counter = 0;
      for(int j=0;j<init_args.length;j++){
        if(init_args[j] != null){
          counter++;
        }
      }

      String[] final_args = new String[counter];
      for(int j=0;j<counter;j++){
        final_args[j] = init_args[j];
      }

      if(final_args[1].equals("list")){
        int[] list = hotelclient.get_list(final_args);
        System.out.println("list received in hotelgw.java");
        for(int j=0;j<list.length;j++){
          try{
            out.writeInt(list[j]);
          }catch (Exception e){
            System.out.println("Error writing to socket: " + e);
            System.exit(1);
          }
        }
      }


      try{
        in.close();
        newsock.close();
      }catch (Exception e){
        System.out.println("Error: "+e);
        System.exit(1);
      }
    }
  }
}

Cクライアント:

#include <stdio.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define PORT 4242
#define TYPES_OF_ROOMS 3
#define BUFFER_SIZE 64

/*Writes message to socket*/
ssize_t writen(int fd, const void *vptr, size_t n)
{
  size_t nleft;
  ssize_t nwritten;
  const int *ptr;

  ptr = vptr;
  nleft = n;
  while(nleft>0){
    if ( ((nwritten = write(fd,ptr,nleft)) <= 0)){
      if (errno == EINTR)
        nwritten = 0;
      else
        return -1;

    }
    nleft -= nwritten;
    ptr += nwritten;
  }
  return n;
}


int create_socket(char* address){
  struct hostent *server_address;
  struct in_addr *addr;
  struct sockaddr_in server_addr;
  socklen_t addrlen;
  char* ip;

  int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if(sockfd<0){
    perror("Error creating socket");
    exit(1);
  }

  server_address = gethostbyname(address);
  if(server_address == NULL){
    fprintf(stderr, "Server not found!\n");
    exit(1);
  }else{
    addr = (struct in_addr*) server_address->h_addr_list[0];
  }

  ip = inet_ntoa(*addr);

  server_addr.sin_family  =  AF_INET;
  server_addr.sin_port    =  htons(PORT);
  server_addr.sin_addr.s_addr  =  inet_addr(ip); 

  addrlen = (socklen_t) sizeof(struct sockaddr_in);

  if(connect(sockfd,(struct sockaddr *) &server_addr, addrlen)){
    perror("Error connecting to server");
    exit(1);
  }

  return sockfd;
}


int main(int argc, char** argv){
  int sockfd, err, i, type1=0, type2=0, type3=0;
  int int_buf[TYPES_OF_ROOMS];
  char string_buf[BUFFER_SIZE];
  char newline = '\n';
  char *end = "end";

  if(argc == 1){
    printf("Usage: hotelgwclient <address> {list,guests,book} [room type] [guest name]\n");
    exit(1);
  }

  sockfd = create_socket(argv[1]);
  printf("Socket created\n");


  if(strcmp(argv[2], "list")==0){
    if(argc != 3){
      printf("Usage: hotelgwclient <address> list\n");
      exit(1);
    }


    printf("list initiated\n");
    writen(sockfd, argv[1], strlen(argv[1]));
    writen(sockfd, &newline , sizeof(newline));
    writen(sockfd, argv[2], strlen(argv[2])); 
    writen(sockfd, &newline, sizeof(newline));
    writen(sockfd, end, strlen(end));
    writen(sockfd, &newline, sizeof(newline));
    printf("Written to socket\n");

    err = read(sockfd, &type1, sizeof(int));
    err = read(sockfd, &type2, sizeof(int));
    err = read(sockfd, &type3, sizeof(int));

    printf("Read from socket\n");
    if(err<0){
      perror("Error reading from socket");
      exit(1);
    }
    /*
    for(i=0;i<TYPES_OF_ROOMS;i++){
      printf("%d\t",int_buf[i]);
    }
    */
    type1 = htonl(type1);
    type2 = htonl(type2);
    type3 = htonl(type3);

    printf("%d\t",type1);
    printf("%d\t",type2);
    printf("%d\t",type3);
    printf("\n");
    return 0;
  }

  printf("Command not recognized.\nUsage: hotelgwclient <address> {list,guests,book} [room type] [guest name]\n");
  exit(1);
}

(NB私はそれが厄介であることを知っています、私はそれが機能するときにそれをクリーンアップします:))。

問題は、listメソッドを呼び出し、Cが応答(3つのint)を読み取ろうとすると、4バイトではなく1バイトしか読み取れないことです。これは、ソケットから読み取る前にsleep()呼び出しを追加すると修正されます。何が起こっているのか、それを修正するために私が何をすべきかを誰かが知っていますか?!

ありがとう!

4

3 に答える 3

2

問題は、最小値が常に1の場合(Javaでも)、必要なだけのデータを読み取ることを想定していることだと思います。

他のバイトよりも1バイト先に取得するのは、BufferedOutputStreamなしでDataOutputStreamを使用しているため、一度に1バイトを送信しているためです。この回避策を使用したくなるかもしれませんが、これは常に可能であるため、一度に1バイトを正しく読み取ることができる必要があるという根本的な問題を隠すだけです。

于 2012-10-19T12:29:00.447 に答える
1

read要求したより少ないバイトを返すのに有効です。そのマニュアルページから:

戻り値
成功すると、読み取られたバイト数が返されます...この数が要求されたバイト数よりも小さい場合でもエラーにはなりません。これが起こる可能性があります

read予想されるバイト数またはエラーが返されるまで、ループで呼び出す必要があります。

unsigned char* p = &type1;
int expected = sizeof(int);
while (expected > 0) {
    err = read(sockfd, p, expected);
    if (err < 0) {
        break;
    }
    p += err;
    expected -= err;
}
于 2012-10-19T12:28:33.923 に答える
0

ブロッキング呼び出しが含まれ、並列に動作する必要がある場合は、実行をブロックしないように、各タスク(読み取り用と書き込み用など)にスレッドを追加する必要があります。

また、受信したすべてのものをバッファに入れて、そこから解析してみてください。pthreadapiを使用してスレッドを実装します。

于 2012-10-19T12:27:28.127 に答える