繁体   English   中英

如何在C中使用ctime()从套接字读取字节

[英]How to read bytes from socket with ctime() in C

目前,我正在做某种练习,尝试通过TCP连接模拟时间协议RFC 868。 我已经用Java完成了服务器,并且已经用C完成了客户端。这是服务器的主要代码行。

private static final long SECONDS_FROM_1900_TO_1970 = 2208988800L; //Long I need in order to calculate the
//time past since 1900. It is because time protocol sets the epoch at 1900 and the java Date class at 
//1970.
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        try{
            int serverPort = 37000;
            ServerSocket receivingConnections = new ServerSocket (serverPort);
            for(;;) { //Infinity loop equivalent to while(true)
              clientConnection = receivingConnections.accept();
              System.out.println("Connection established with client IP: " +clientConnection.getInetAddress());
                try{
                    in = new DataInputStream(clientConnection.getInputStream());
                    out = new DataOutputStream(clientConnection.getOutputStream());
                    Date actualTime = new Date();//Date gives us the second for the epoch until 1970. Had to import utils.date
                    long secondsSince1970 = (actualTime.getTime())/1000;//I divide the time by 1000 because actualTime.getTime()
                    //returns me the result in ms
                    long secondsFromTheBeginning = secondsSince1970 + SECONDS_FROM_1900_TO_1970; //Total seconds i do need to calculate
                    //the time from 1990 in order to respect RFC 868 specification

                    byte[] actualTimeToBytes = new byte[4]; //Byte structure I need to send to the client. 4 bytes = 32 bits.
                    //With the next 4 lines of code I will introduce the whole long into 4 bytes. A long takes 4 bytes = 32 bits.
                    actualTimeToBytes[0] = (byte) ((secondsFromTheBeginning & 0x00000000FF000000L) >> 24);
                    actualTimeToBytes[1] = (byte) ((secondsFromTheBeginning & 0x0000000000FF0000L) >> 16);
                    actualTimeToBytes[2] = (byte) ((secondsFromTheBeginning & 0x000000000000FF00L) >> 8);
                    actualTimeToBytes[3] = (byte) (secondsFromTheBeginning & 0x00000000000000FFL);
                    String s = new String(actualTimeToBytes);
                    System.out.println(secondsFromTheBeginning); //The actual time being sent over the socket..
                    System.out.println(s); // The actual byte being sent over the socket.
                    out.write(actualTimeToBytes);//Here I send to the receiver the time in Byte form via the socket
                    out.flush();
                    System.out.println("The time was indeed sent to: " +clientConnection.getInetAddress());


                } catch (IOException e){System.out.println("Error: "+e.getMessage()); }
                finally { if (clientConnection != null) {

                    System.out.println("Connection finished with client IP: " +clientConnection.getInetAddress());
                    clientConnection.close(); 
                }
            }
        } 

    } catch (IOException ex) {
        System.err.println(ex);
    }
    }

服务器工作正常,但是在客户端执行时出现问题。 客户代码:

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <time.h>


/*****************************************************
 * Reproduced from Unix Network Programming
                W.Richard Stevens
                Prentice Hall Software Series 1990
 * Definitions for TCP and UDP client/server programs
 */
#include    <sys/types.h>
#include    <sys/socket.h>
#include    <netinet/in.h>
#include    <arpa/inet.h>
/*****************************************************/


#define SERVERPORT 37000
#define SERVERIP "192.168.0.18"
#define TIMELENGTHBYTES 4

/* 
 * Program a new function that reads four bytes from the socket:
 * int readDate(...)
 */
int readDate(int *sockfd){

     int    n;
     char   buffer[4];
     unsigned long  lorovrigida;
    n = read(*sockfd, buffer, 4);  
   lorovrigida = (buffer[0]<<24) + (buffer[1]<<16) + (buffer[2]<<8) + (buffer[3]);
   lorovrigida-=2208988800;

    printf(ctime(&lorovrigida));

    if ( n < 0 ) {
    printf("TIMECLNT: Error in read()\n");
    exit(EXIT_FAILURE);
    }
}
int connectToServer(char *ip, int port, int *sockfd) {
    int rv = 0;    
    struct sockaddr_in serv_addr;

    char buf[4];

    bzero((char *) &serv_addr, sizeof (serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(SERVERIP);
    serv_addr.sin_port = htons(SERVERPORT);

    if ((*sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        rv = -1;
    } else {

        if (connect(*sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
            rv = -2;
        }
    }

    return rv;
}

int main(int argc, char** argv) {

    int e, sockfd;


    if ((e = connectToServer(SERVERIP, SERVERPORT, &sockfd)) != 0) {
        printf("Error on call to connectToServer: %d\n", e);
        exit(e);
    }

    printf("Successfully connected to server\n");
    if(sockfd==NULL)
        printf("El socket esta vacio\n");
    fflush(stdout);    

    /*
     * Call the readDate() function and print out the result:
     */
    readDate(&sockfd);



    return (EXIT_SUCCESS);
}

主要问题是我真的不知道如何读取接收到的4个字节。 当我打印出lorovrigida时,这似乎是一个巨大且随机的数字。

我该如何正确阅读? 是因为我使用的是无符号长型吗? 我被困住了,因为我尝试了很多不同的方法,但没有任何效果。

谢谢您的帮助。

我不认为这是字节序问题,因为您的java server已经处理了。

在您的客户端char buffer[4]; ,则将其声明为有signed ,进行移位时,当某个字节的最高位为1时,就不会获得正确的结果。定义为unsigned char buffer[4];

 unsigned char ua = 0x80;
 unsigned int b = ua << 1;
 printf("%u\n", b);

 char a = 0x80;
 unsigned int c = a << 1;
 printf("%u\n", c);

结果:

256
4294967040

32位结果的重建是一个问题,从可能签名的4个char开始。

假设char被签名并且2的补码...

添加buffer[3] ,它首先会进行通常的整数提升。 这意味着类似1000_0000 (-128)的位模式变为1111_1111_...1000_0000 前1位的数量取决于int位的宽度。


为了避免所有这些符号扩展,最好使用无符号类型。

IMO:建议#4

// Method 1 - cast buffer
int readDate(int *sockfd) {
  char   buffer[4];
  int    n;
  unsigned long  lorovrigida;
  n = read(*sockfd, buffer, 4);  
  if ( n < 0 ) {
    printf("TIMECLNT: Error in read()\n");
    exit(EXIT_FAILURE);
  }
  lorovrigida = ((unsigned char)buffer[0]<<24) + ((unsigned char)buffer[1]<<16) + 
      ((unsigned char)buffer[2]<<8) + ((unsigned char)buffer[3]);
  ....
}

// Method 2 - use unsigned char type
int readDate_2(int *sockfd) {
  unsigned char buffer[4];
  ...
  lorovrigida = (buffer[0]<<24) + (buffer[1]<<16) + 
      (buffer[2]<<8) + (buffer[3]);
  ....
}

// Method 3 - exact size types
int readDate_2(int *sockfd) {
  uint8_t buffer[4];
  ...
  lorovrigida = (buffer[0]<<24) + (buffer[1]<<16) + 
      (buffer[2]<<8) + (buffer[3]);
  ....
}

// Method 4 - * by unsigned
int readDate_2(int *sockfd) {
  uint8_t buffer[4];
  ...
  lorovrigida = buffer[0]*0x1000000LU + buffer[1]*0x10000LU + 
      buffer[2]*0x100u + buffer[3];
  ....
}

// Method 5 - successive or-ing
int readDate_2(int *sockfd) {
  uint8_t buffer[4];
  ...
  lorovrigida = buffer[0];
  lorovrigida = lorovrigida << 8 | buffer[1];
  lorovrigida = lorovrigida << 8 | buffer[2];
  lorovrigida = lorovrigida << 8 | buffer[3];

  ....
}

如果系统使用16位无符号,则方法1-3会具有可移植性。

优化的编译器可能会为这些方法生成类似的代码。

此外:在我的编译器中,代码还可以通过使用uint32_t之类的固定宽度而不是unsigned long (64位)来受益。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM