Address: http://blog.csdn.net/ffb/article/details/17437101
When using nc to access the memcache service, it is found that the set command always fails, but other commands are available. For telnet, everything is normal, and it is suspected of a server bug. It is worth studying.
The nc command is:
nc 127.0.0.1 11212
The telnet command is as follows:
telnet 127.0.0.1 11212
So I tried to use wireshark to capture packets and analyze the data difference,
Telnet request data is as follows:
0000 73 65 74 20 70 79 77 20 31 20 30 20 33 0d 0a 31 set pyw 1 0 3..10010 30 30 0d 0a 00..
The request data of nc is as follows:
0000 73 65 74 20 70 79 77 20 31 20 30 20 33 0a set pyw 1 0 3.0000 31 30 30 0a 100.
It is found that the return letter sent by nc is 0A, And the return letter sent by telnet is 0D 0A, which should be caused by this difference, but other commands sent by nc can be correctly executed, we suspect that the server code has bugs.
View the source code and process the code in the Command Format in:
Memcached. c: try_read_command
2455 cont = el + 1; 2456 if ((el - c->rcurr) > 1 && *(el - 1) == '\r') { 2457 el--; 2458 } 2459 *el = '\0';
Here, el is
2433 el = memchr(c->rcurr, '\n', c->rbytes);
It seems that the code is okay. As a result, the reading command and judgment position are in drive_machine (), where c-> state is used to control the processing flow, so you only need to track the changes to this variable. So tracking:
$ gdb ./memcached(gdb) set args -A 11212(gdb) b try_read_commandBreakpoint 1 at 0x409e79: file memcached.c, line 2422.(gdb) r
Client Input
get pywENDset pyw 0 0 3100
It can be seen that for the set command from ns, after try_read_command, the status value changes to conn_nread rather than conn_mwrite, meaning that the command parameters need to be read again. Therefore, the conn_nread breakpoint is added.
(Gdb) B 2848
After debugging, you can see this Code:
2848 if (c->rlbytes == 0) { 2849 complete_nread(c); 2850 break; 2851 }
When I followed in, I found very suspicious code:
948 if (strncmp(ITEM_data(it) + it->nbytes - 2, "\r\n", 2) != 0) {
Change
948 if (strncmp(ITEM_data(it) + it->nbytes - 2, "\r\n", 2) != 0 && strncmp(ITEM_data(it) + it->nbytes - 1, "\n", 1) != 0) {
Compile and run the command, re-execute the preceding command, and press enter once to find that the data is successfully saved.
Why do we need to press enter once? The reason is that the entire state flow on the memcache server is driven by the number of bytes that have been read. When you enter the set command, the process_update_command function sets a number of expected bytes to the variable conn: rlbytes. The expected value is calculated by \ r \ n by default. For example, if you want to input three more bytes, this value is set to 5.
Since the processing methods in the Code are highly bound to \ r \ n, such as item_make_header (), if you want to completely solve this problem, it is best to analyze the carriage return type of the terminal after the first command, unified identification, and improves the compatibility of related codes based on the identification. However, due to the many modifications involved, this study is now available.
Before the end, I changed my mind. The problem involved here is that the memcache Communication Protocol stipulates that \ r \ n is the standard command end method, so the server code does not need to be modified, as long as the client sends \ r \ n as the carriage return according to the Protocol requirements (check whether it can comply with the requirements before changing), man ran the nc and tried the following command:
$ nc -C 127.0.0.1 11211set pyw 1 0 3100STORED
OK. Solve the problem.