Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby客户端无法从C服务器读取:socket.get挂起_C_Ruby_Sockets_Networking_Client Server - Fatal编程技术网

Ruby客户端无法从C服务器读取:socket.get挂起

Ruby客户端无法从C服务器读取:socket.get挂起,c,ruby,sockets,networking,client-server,C,Ruby,Sockets,Networking,Client Server,我有一个C语言的服务器和一个Ruby语言的客户端。我的ruby客户机能够成功地将字符串发送到我的C服务器,但它无法接收来自它的任何输入 更具体地说,client.rb中我的“recv”方法中的“get”方法挂起。启动my client.rb程序如下所示: [user]$ ruby client.rb ## CLIENT STARTED ## user: myuser //user enters username and password here password: mypass

我有一个C语言的服务器和一个Ruby语言的客户端。我的ruby客户机能够成功地将字符串发送到我的C服务器,但它无法接收来自它的任何输入

更具体地说,client.rb中我的“recv”方法中的“get”方法挂起。启动my client.rb程序如下所示:

[user]$ ruby client.rb
## CLIENT STARTED ##
user: myuser       //user enters username and password here
password: mypass   // It hangs after this line, so I press ctrl-C

^Cclient.rb:27:in `gets': Interrupt     //This is the output after pressing ctrl-C
from client.rb:27:in `verifyUser'
from client.rb:40:in `main'
from client.rb:48
而我的服务器的输出将是:

## SERVER STARTED ##
[Wed Aug 13 12:19:43 2014]  21 bytes  0 myuser mypass
write succeed
request processed
根据我的输出,向客户端写入成功。但是我的ruby客户端在recv方法中调用socket.get时挂起。我也尝试过使用socket.read,但它也挂起了。我只需要从我的服务器获取第一个字节或一行输入

为什么我的客户端不能从服务器接收输入

应该发生的事情清单如下:

  • 服务器启动
  • 客户端启动,用户输入用户名和密码
  • 服务器接收用户名和密码
  • 服务器向客户端发送字符串
  • 客户端从服务器接收字符串
  • 客户端根据字符串执行一些操作
客户端.rb

$ip = '127.0.0.1'
$port = 29008

def send(msg)
  socket = TCPSocket.new($ip, $port)
  socket.write(msg)
  socket.close
end

def recv
  socket = TCPSocket.new($ip, $port)
  data = socket.gets
  socket.close
  data
end

def verifyUser(user, pw)
  send("0 #{user.chomp!} #{pw.chomp!}")
  recv =~ /^0/
end


def main

  puts "## CLIENT STARTED ##"
  print "user: "
  user = gets
  print "password: "
  pw = gets

  if verifyUser(user, pw) then
    puts "user verified"
  else
    puts "wrong user or password"
  end

end

main
server.c

/* PROCESS REQUEST */
void processRequest(char *input, int cfd) {

  int option = 0;
  char *ch = "0";

  if (option == 0) {

     if (send(cfd, ch, strlen(ch), 0) < 0) {
        puts ("write error");
     } else {
        puts ("write succeed");
     }

  } else {
     puts("option is not valid");
  }
}



int main() {

  int sfd, cfd;
  int optval = 1;
  char buffer[2000];
  char input[2000];
  int len;
  int idx = 0;
  time_t currTime;
  char *time_str;


  struct sockaddr_in saddr, caddr;


  sfd = socket(AF_INET, SOCK_STREAM, 0);


  saddr.sin_family = AF_INET; /* Set address family to IPv4 Internet */
  saddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any internet address */
  saddr.sin_port = htons(29008); /* Set server port to 29008 */

 setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);

  bind(sfd, (struct sockaddr *)&saddr, sizeof(saddr));


  listen(sfd, 1);

  printf("## SERVER STARTED ##\n");

  while (1) {



        if ((cfd = accept(sfd, (struct sockaddr *)NULL, NULL)) < 0) {
                puts("client connection failed");
        }

        /* get time of message */
        currTime = time(NULL);
        time_str = asctime(localtime(&currTime));
        time_str[strlen(time_str) - 1] = '\0';


        /* ensure that all everything is received from client */
        while ((len = recv(cfd, buffer, 2000, 0)) > 0) {

                buffer[len] = '\0';

                if (idx == 0) {
                   strcpy(input, buffer);
                } else {
                   strcat(input, buffer);
                }

                /* log message */
                printf ("[%s]  %d bytes  %s\n", time_str, len, input);

                idx++;
        }

        if (len < 0) {
                printf("recieve failed\n");
                return 1;
        }

        processRequest(input,cfd);
        puts("request processed");


        close(cfd);

        idx = 0;
        input[0] = '\0';
  }

  return 0;
}
/*处理请求*/
无效处理请求(字符*输入,整数cfd){
int选项=0;
char*ch=“0”;
如果(选项==0){
如果(发送(cfd,ch,strlen(ch),0)<0){
puts(“写入错误”);
}否则{
卖出(“写入成功”);
}
}否则{
看跌期权(“期权无效”);
}
}
int main(){
国际财经事务及库务局;
int optval=1;
字符缓冲区[2000];
字符输入[2000];
内伦;
int-idx=0;
时不我待;
字符*时间长度;
caddr saddr中的结构sockaddr_;
sfd=套接字(AF_INET,SOCK_STREAM,0);
saddr.sin_family=AF_INET;/*将地址系列设置为IPv4 Internet*/
saddr.sin_addr.s_addr=htonl(INADDR_ANY);/*任何互联网地址*/
saddr.sin_port=htons(29008);/*将服务器端口设置为29008*/
setsockopt(sfd、SOL_插座、SO_REUSEADDR和optval、optval尺寸);
绑定(sfd,(struct sockaddr*)和saddr,sizeof(saddr));
聆听(sfd,1);
printf(“###服务器已启动##\n”);
而(1){
如果((cfd=accept(sfd,(struct sockaddr*)NULL,NULL))<0){
puts(“客户端连接失败”);
}
/*获取消息的时间*/
currTime=时间(空);
time_str=asctime(localtime(&currTime));
时间序列[strlen(time-str)-1]='\0';
/*确保从客户处收到所有信息*/
而((len=recv(cfd,buffer,2000,0))>0){
缓冲区[len]='\0';
如果(idx==0){
strcpy(输入、缓冲);
}否则{
strcat(输入、缓冲);
}
/*日志消息*/
printf(“[%s]%d字节%s\n”,时间长度,输入);
idx++;
}
if(len<0){
printf(“接收失败\n”);
返回1;
}
processRequest(输入,cfd);
出售(“已处理请求”);
关闭(cfd);
idx=0;
输入[0]='\0';
}
返回0;
}
编辑

  • 我已经修改了我的server.c代码,以反映我现在的情况。我将send方法中的strlen(输入)参数更改为strlen(ch)。问题仍然存在

  • 我已经通过telnet测试了我的服务器,结果是一样的。我可以向服务器写入数据,但不能从服务器读取数据。这让我相信我的Ruby客户端没有任何问题。这一定是我的服务器发送数据的方式有问题

修改后的答案:

1) 在ruby代码中,您没有使用相同的套接字从服务器进行写和读。在verifyUser中创建套接字并将其传递到send/recv中-这样可以保持与服务器的连接

def send(s, msg)
  print("sending: '" + msg + "'\n")
  s.write(msg)
  s.flush
end

def recv(s)
  print("in recv");
  data = s.recv(1024)
  print("got data: " + data);
  data   
end

def verifyUser(user, pw)
  socket = TCPSocket.new($ip, $port)
  send(socket,"0 #{user.chomp!} #{pw.chomp!}\0")
  resp = recv(socket) 
  socket.close
  resp =~ /^0/
end
2) 在c服务器中-len=recv while循环-您真的需要while循环吗?服务器再次读取命令和循环。它以前工作的唯一原因是,您关闭了套接字,然后recv出现错误,跳出循环并处理了请求。如果将processRequest放在带有时间戳的printf下面,您将看到服务器确实发送了响应。如果你整理一下ruby客户端的套接字,你会得到相应的响应

  • Ruby:send()和recv()都应该使用相同的套接字,而不是各自使用不同的新套接字
  • Ruby:gets()依赖于换行符来知道输入何时完成
  • C:与#2类似,您的recv()正在等待2000字节结束循环,而不是换行符或任何东西
  • Ruby代码:

    def send(socket, msg)
      socket.puts(msg) # puts() adds a newline for the server.
      socket.flush     # Probably not necessary.
    end
    
    def recv(socket)
      # gets() doesn't end until receives a newline.
      socket.gets
    end
    
    def verifyUser(user, pw)
      response = ''
      
      # Use 1 socket for both send/recv.
      # Can use open() with a block to auto-close
      #   at the end of the block.
      TCPSocket.open($ip, $port) do |socket|
        send(socket,"0 #{user.chomp!} #{pw.chomp!}")
        response = recv(socket)
      end
      
      response =~ /^0/
    end
    
    C代码:

    void processRequest(char *input, int cfd) {
      int option = 0;
      char *ch = "0\n"; // Newline!
    
      //...
    }
    
    //...
    
            /* ensure that all everything is received from client */
            while ((len = recv(cfd, buffer, 2000, 0)) > 0) {
    
                    buffer[len] = '\0';
                    
                    if (idx == 0) {
                       strcpy(input, buffer);
                    } else {
                       strcat(input, buffer);
                    }
    
                    /* log message */
                    printf ("[%s]  %d bytes  %s\n", time_str, len, input);
    
                    idx++;
                    
                    // Note that this is just a simple version.
                    // You probably want to store a substring into input.
                    // Then save the rest of the substring in the buffer.
                    // Include "stdbool.h" if don't want to use an int.
                    int has_newline = 0;
                    
                    for(int i = 0; i < len; ++i) {
                      if(buffer[i] == '\n') {
                        printf("Breaking out of loop.\n");
                        has_newline = 1;
                        break;
                      }
                    }
                    
                    if(has_newline == 1) {
                      break;
                    }
            }
    
    //...
    
    void processRequest(字符*输入,int cfd){
    int选项=0;
    char*ch=“0\n”;//换行符!
    //...
    }
    //...
    /*确保从客户处收到所有信息*/
    而((len=recv(cfd,buffer,2000,0))>0){
    缓冲区[len]='\0';
    如果(idx==0){
    strcpy(输入、缓冲);
    }否则{
    strcat(输入、缓冲);
    }
    /*日志消息*/
    printf(“[%s]%d字节%s\n”,时间长度,输入);
    idx++;
    //请注意,这只是一个简单的版本。
    //您可能希望将子字符串存储到输入中。
    //然后将子字符串的其余部分保存在缓冲区中。
    //如果不想使用int,请包括“stdbool.h”。
    int具有_新行=0;
    对于(int i=0;i
    很抱歉,我编辑了processRequest meth