📝 ASN.1 data types explained (23 MCQs)
📖 From Data Communication and Networks • 27. Network Management • 23 questions available
What is ASN.1 data types explained?
ASN.1 provides primitive types like BOOLEAN, INTEGER, and OCTET STRING for simple values, and constructed types like SEQUENCE, SET, and CHOICE for grouping data; it also includes specialized SNMP types such as Counter32, Gauge32, and IpAddress to represent network-specific information precisely.
📝 All ASN.1 data types explained MCQs
Q1. In the server code, variable `int s;` holds the socket descriptor. If the program mistakenly declares it as `float s;`, what immediate effect would occur when `socket()` returns a large integer value?
📖 Explanation: Using a floating‑point type for a descriptor causes the large integer returned by `socket()` to be converted to a floating‑point representation, losing precision and potentially yielding a negative or non‑integer value. Subsequent system calls expect a valid integer descriptor, so the program will likely fail to communicate or produce errors.
Q2. Why does the client program use `char *servName;` instead of `char servName[256];` when handling command‑line arguments?
📖 Explanation: The command‑line argument is already stored in memory by the runtime; assigning a `char *` simply points to that existing string. Using a fixed‑size array would require copying the data, which is unnecessary and could waste stack space if the name is short. Hence the pointer is the most efficient choice.
Q3. If `int n;` is used to store the number of bytes received from `recv()`, what logical error could arise if `n` is later compared to a constant defined as `#define MAX 256` using the expression `if (n > MAX)`?
📖 Explanation: `recv()` returns a negative value on error. Storing that in a signed `int` and then testing `n > MAX` would treat an error as a valid byte count, potentially causing the program to process invalid data. Proper error checking should test for `n < 0` before any size comparison.
Q4. Consider the line `char buffer[256 + 1];`. Which reasoning best explains the use of `+ 1` in this declaration?
📖 Explanation: The buffer is intended for raw data transfer, not null‑terminated strings, so the extra byte is not for a terminator. However, many protocols prepend a length byte or need a sentinel value; allocating one more byte anticipates such a requirement, ensuring the buffer can hold the maximum payload plus the additional control byte.
Q5. When the server declares `struct sockaddr_in serverAddr;`, what inference can be made about the type of network communication it intends to use?
📖 Explanation: `struct sockaddr_in` is the standard structure for IPv4 socket addresses, applicable to both stream (TCP) and datagram (UDP) sockets. Its presence indicates the program will operate over IPv4, but does not restrict the transport protocol; the later `listen` or `connect` calls determine TCP versus UDP.
Q6. If the server mistakenly writes `serverAddr.sin_family = AF_INET6;` while still using `struct sockaddr_in`, what deduction follows regarding the program’s behavior?
📖 Explanation: Assigning `AF_INET6` to a field designed for IPv4 does not automatically adjust the structure layout. The `bind` system call will interpret the mismatched family as an error, typically returning `EINVAL`. The program will not start listening, highlighting the importance of matching address families with their corresponding structures.
Q7. Why is the pointer `char *ptr = buffer;` introduced after the buffer declaration, and what logical effect does advancing `ptr` have during data reception?
📖 Explanation: `ptr` is initialized to the start of `buffer` and then incremented as bytes are received. This technique lets the program write incoming data to successive locations while preserving the original buffer address for later processing or printing. Advancing `ptr` does not modify `buffer` itself; it merely changes where the next write occurs.
Q8. Compare the use of `int` for socket descriptors with using `void *` as a generic handle. Which analytical conclusion is most accurate?
📖 Explanation: Socket descriptors are defined by the POSIX API as integer values. Using `int` aligns with the standard, ensuring portability across platforms. A `void *` would require casting and could obscure the nature of the descriptor, potentially leading to misuse or compilation warnings. Therefore, `int` remains the preferred choice.
Q9. Evaluate the impact of declaring `char *string;` without allocating memory before assigning `string = argv[3];`. Which statement best reflects the program’s safety?
📖 Explanation: `argv[3]` is provided by the runtime and points to a null‑terminated string from the command line. Assigning its address to `string` does not copy the data but merely references it. As long as the program does not modify the string or exceed its length, this usage is safe and common in C programs.
Q10. The server code uses `memset(&servAddr, 0, sizeof(servAddr));`. What conceptual reason justifies zero‑initializing this structure before setting fields?
📖 Explanation: Zero‑initializing ensures that all fields not explicitly set (such as padding bytes) contain known values, preventing accidental leakage of garbage data into system calls like `bind`. This practice avoids undefined behavior that could arise from uninitialized fields, especially on architectures where padding may be transmitted.
Q11. Synthesize a scenario where changing `char buffer[256 + 1];` to `char buffer[512];` could introduce a subtle bug in the client program. Which explanation is most plausible?
📖 Explanation: Increasing the buffer size without adjusting the logic that tracks the number of valid bytes can lead to processing of uninitialized memory. If the program assumes the buffer contains only the received payload, residual data from previous operations may be mistakenly transmitted or printed, causing incorrect output.
Q12. If the client incorrectly declares `int servPort;` but later assigns `servPort = atoi(arg[2]);` where `arg[2]` is a non‑numeric string, what logical mistake does this represent?
📖 Explanation: `atoi` returns 0 when conversion fails, which is a valid (though usually undesired) port number. Not checking the result can cause the client to attempt a connection on an unintended port, leading to connection failures or unintended behavior. Proper error handling should verify that the conversion succeeded and the result lies within the valid port range.
Q13. Analyze the effect of declaring `struct sockaddr_in serverAddr;` as a global variable versus a local variable inside `main()`. Which outcome best reflects the difference?
📖 Explanation: Placing the address structure globally makes it accessible to any function, which could unintentionally modify its fields, especially in multi‑threaded contexts. Declaring it locally confines its lifetime to `main`, reducing side effects and improving encapsulation. However, both scopes can be zeroed explicitly, so the primary concerns are encapsulation and thread safety.
Q14. When the server uses `int n;` to store the return value of `recv()`, why might a developer prefer `ssize_t n;` instead?
📖 Explanation: The POSIX `recv` function returns a signed size type (`ssize_t`) that can represent both the number of bytes read and negative error codes. Using `ssize_t` ensures the variable can hold the full range of possible return values without truncation, improving correctness and portability.
Q15. If the server mistakenly changes `char buffer[256 + 1];` to `char buffer[256];` but still writes a null terminator after the received data, what consequence follows?
📖 Explanation: Writing a null terminator at `buffer[length]` when the buffer size equals the maximum payload (256) writes to index 256, which is outside the allocated array (indices 0‑255). This out‑of‑bounds write can corrupt adjacent memory, leading to crashes or security vulnerabilities.
Q16. Explain why `int s;` is preferred over `unsigned int s;` for a socket descriptor, considering potential system call semantics. Which conceptual point is most accurate?
📖 Explanation: POSIX defines socket descriptors as non‑negative integers, but functions like `socket()` return `-1` on error. Using a signed `int` allows the program to detect this error condition directly. An unsigned type would wrap `-1` to a large positive value, obscuring the failure. Hence, signed `int` aligns with the API contract.
Q17. What logical reasoning explains why `char *ptr = buffer;` is used instead of directly indexing `buffer[i]` inside the receive loop?
📖 Explanation: Using a pointer that is incremented after each `recv` call eliminates the need for an explicit index variable, making the loop body shorter and clearer. The pointer always points to the next free position in the buffer, and the code can directly pass `ptr` to subsequent functions without calculating offsets.
Q18. Which factual statement correctly defines the purpose of `struct sockaddr_in` fields `sin_family`, `sin_port`, and `sin_addr`?
📖 Explanation: `struct sockaddr_in` is the IPv4 socket address structure. `sin_family` must be set to `AF_INET` to indicate IPv4. `sin_port` stores the port number in network byte order, typically set using `htons`. `sin_addr` holds the IPv4 address, often set via `inet_pton` or `INADDR_ANY`. These fields together define where the socket will bind or connect.
Q19. In the client program, `int s;` is used for the socket descriptor. If the code were ported to a 64‑bit system where descriptors are 64‑bit values, what conceptual issue might arise?
📖 Explanation: While most POSIX implementations keep socket descriptors as 32‑bit integers even on 64‑bit platforms, some systems may define them as larger types. Using a plain `int` could truncate a 64‑bit descriptor, leading to invalid handles and runtime errors. Portable code should use the `socket_t` or `int` as defined by the API, but awareness of potential size differences is essential.
Q20. When the server declares `int n;` and later uses `if (n == -1)`, what conceptual relationship between `n` and error handling does this illustrate?
📖 Explanation: POSIX system calls, including `recv()`, return `-1` to indicate an error, setting `errno` to describe the failure. Checking for `n == -1` follows this convention, allowing the program to handle errors appropriately. This pattern is fundamental to robust network programming.
Q21. Why might a programmer choose `size_t len;` instead of `int len;` for storing the length of a string to be echoed?
📖 Explanation: `size_t` is the unsigned type returned by `strlen` and other size‑related functions, guaranteeing a non‑negative value and accommodating the full range of possible string lengths on the target platform. Using `int` could truncate large lengths or permit negative values, which are semantically incorrect for a size.
Q22. If the client program replaces `char *servName;` with `char servName[128];` but forgets to copy the command‑line argument into the array, what logical error will result?
📖 Explanation: Without copying the provided hostname into `servName`, the array remains filled with zeros (or indeterminate data), leading to an empty or invalid hostname string. The subsequent `connect` call will fail to resolve the address, typically resulting in a DNS error and termination of the client.
Q23. Which factual definition accurately describes the role of `AF_INET` in the socket API?
📖 Explanation: `AF_INET` is a constant defined in the sockets API that designates the IPv4 address family. It tells the system that the socket will use IPv4 addresses, influencing how address structures are interpreted and how routing is performed. It is distinct from `AF_INET6`, which is used for IPv6.