Question: What does the code below output? Why?
printf("connect success\n");
send(sock, "A", 1, 0);
send(sock, "B", 1, 0);
send(sock, "C", 1, 0);
close(sock);
do {
r = recv(client, buf, sizeof(buf), 0);
if (r > 0) {
printf("Recv: %s\n", buf);
}
}while (1);
close(client);
Complete code client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
int sock = 0;
struct sockaddr_in addr = {0};
int len = 0;
char buf[128] = {0};
char input[32] = {0};
int r = 0;
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1) {
printf("socket error\n");
return -1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(8888);
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
printf("connect error\n");
return -1;
}
printf("connect success\n");
send(sock, "A", 1, 0);
send(sock, "B", 1, 0);
send(sock, "C", 1, 0);
close(sock);
return 0;
}
Complete code: server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
int server = 0;
struct sockaddr_in saddr = {0};
int client = 0;
struct sockaddr_in caddr = {0};
socklen_t asize = 0;
int len = 0;
char buf[32] = {0};
int r = 0;
server = socket(PF_INET, SOCK_STREAM, 0);
if (server == -1) {
printf("server socket error\n");
return -1;
}
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(8888);
if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
printf("server bind error\n");
return -1;
}
if (listen(server, 1) == -1) {
printf("server listen error\n");
return -1;
}
printf("server start success\n");
while (1) {
asize = sizeof(caddr);
client = accept(server, (struct sockaddr*)&caddr, &asize);
if (client == -1) {
printf("client accept error\n");
return -1;
}
printf("client: %d\n", client);
do {
r = recv(client, buf, sizeof(buf), 0);
if (r > 0) {
printf("Receive: %s\n", buf);
}
} while (r > 0);
close(client);
}
close(server);
return 0;
}
output
server start success
client: 4
Receive: ABC
tips
send buffer
- The data first enters the send buffer, and then is sent to the remote host by the operating system
receive buffer
- The remote data is accepted by the operating system and put into the receive buffer
- Afterwards the application reads the data from the receive buffer
"Problems" in TCP Application Programming
The receiver of the data has no way of knowing how the data was sent
The receiver has no way of knowing that "ABC"
was sent separately!
Expectations in Network Programming
- Send a complete message at a time, receive a complete message at a time
- No message sticking even if there are multiple messages in the receive buffer
- The message covers information such as data type and data length
Application layer protocol design
What is an agreement?
- A protocol is a set of rules , standards or predetermined sets established by both parties for data exchange
The role of protocols in data transmission
- Both communication parties can correctly send and receive data according to the agreement
- The communication parties can explain the meaning of the data according to the agreement
Protocol Design Example
- Goal: Design a protocol that can be used for data transfer
The complete message contains
- Data header: data type (ie: data area usage, fixed length)
- Data length: data area length (fixed length)
- Data area: byte data (variable length area)
上图可知:
消息至少 12 个字节(消息头 + 数据长度)
通过计算消息的总长度,能够避开数据粘连的问题
typedef struct {
unsigned short type;
unsigned short cmd;
unsigned short index;
unsigned short total;
unsigned int length;
unsigned char payload[]; // 柔性数组
}Message;
Programming experiment: application layer protocol design and implementation
client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "message.h"
int main()
{
int sock = 0;
struct sockaddr_in addr = {0};
int len = 0;
char buf[128] = {0};
char input[32] = {0};
int r = 0;
Message *pm = NULL;
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1) {
printf("socket error\n");
return -1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(8888);
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
printf("connect error\n");
return -1;
}
printf("connect success\n");
pm = Message_New(0, 0, 1, 3, "A", 1);
send(sock, pm, sizeof(Message) + 1, 0);
pm = Message_New(0, 0, 2, 3, "B", 1);
send(sock, pm, sizeof(Message) + 1, 0);
pm = Message_New(0, 0, 3, 3, "C", 1);
send(sock, pm, sizeof(Message) + 1, 0);
close(sock);
return 0;
}
server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
int server = 0;
struct sockaddr_in saddr = {0};
int client = 0;
struct sockaddr_in caddr = {0};
socklen_t asize = 0;
int len = 0;
char buf[32] = {0};
int r = 0;
server = socket(PF_INET, SOCK_STREAM, 0);
if (server == -1) {
printf("server socket error\n");
return -1;
}
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(8888);
if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
printf("server bind error\n");
return -1;
}
if (listen(server, 1) == -1) {
printf("server listen error\n");
return -1;
}
printf("server start success\n");
while (1) {
asize = sizeof(caddr);
client = accept(server, (struct sockaddr*)&caddr, &asize);
if (client == -1) {
printf("client accept error\n");
return -1;
}
printf("client: %d\n", client);
do {
r = recv(client, buf, sizeof(buf), 0);
if (r > 0) {
int i = 0;
for (i=0; i<r; ++i) {
printf("%02x", buf[i]);
}
printf("\n");
}
} while (r > 0);
close(client);
}
close(server);
return 0;
}
output
0000000001000300010000004100000000020003000100000042000000000300
03000100000043
Thinking: How to encapsulate protocol details (only the relational message itself) at the code layer?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。