eastnow 2015-03-24
编写服务端程序server.c
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#define MAXLINE 1024
int main()
{
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1)
{
printf("socket error[%d]:%s\n", errno, strerror(errno));
exit(errno);
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(55555);
if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
{
printf("bind error[%d]:%s\n", errno, strerror(errno));
exit(errno);
}
if (listen(listen_fd, 3) == -1)
{
printf("listen error[%d]:%s\n", errno, strerror(errno));
exit(errno);
}
while (1)
{
struct sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(client_addr));
int len = sizeof(client_addr);
int client_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &len);
if (client_fd == -1)
{
printf("accept error[%d]:%s\n", errno, strerror(errno));
continue;
}
char rb[100] = {0};
int recv_len = recv(client_fd, rb, MAXLINE, 0);
if (recv_len == -1)
{
printf("recv error[%d]:%s\n", errno, strerror(errno));
continue;
}
printf("recv[%d]:%s\n", recv_len, rb);
strcat(rb, ", has been received by server, the msg from server");
if (send(client_fd, rb, strlen(rb), 0) == -1)
{
printf("send error[%d]:%s\n", errno, strerror(errno));
continue;
}
printf("send success\n");
close(client_fd);
}
close(listen_fd);
}代码说明:
函数原型: int socket(int domain, int type, int protocol)中的参数protocol取值的取值见 netinet/in.h (结合参考/etc/protocols文件)
编写客户端程序client.c
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h>
#include <string.h>
#define MAXLINE 1024
int main()
{
int client_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client_fd == -1)
{
printf("socket error[%d]:%s\n", errno, strerror(errno));
exit(errno);
}
struct sockaddr_in target_addr;
memset(&target_addr, 0, sizeof(target_addr));
target_addr.sin_family = AF_INET;
target_addr.sin_port = htons(55555);
if (inet_pton(AF_INET, "127.0.0.1", &target_addr.sin_addr) < 0)
{
printf("inet_ptonl error[%d]:%s\n", errno, strerror(errno));
exit(errno);
}
if (connect(client_fd, (struct sockaddr *)&target_addr, sizeof(target_addr)) < 0)
{
printf("connect error[%d]:%s\n", errno, strerror(errno));
exit(errno);
}
char sb[500]={0};
strcpy(sb, "client message");
if (send(client_fd, sb, strlen(sb), 0) < 0)
{
printf("send error[%d]:%s\n", errno, strerror(errno));
exit(errno);
}
printf("send success\n");
char rb[MAXLINE]={0};
if (recv(client_fd, rb, MAXLINE, 0) < 0)
{
printf("recv error[%d]:%s\n", errno, strerror(errno));
exit(errno);
}
printf("recv from server:%s\n", rb);
}编译
运行
1. 启动server
2. tcpdump观察
3. 启动client
以上三步,把结果一起贴出来了,需要启动三个终端,并且按顺序运行以上三个命令
观察监听状态
分析
1. server执行完lisetn函数的时候, 开始监听
2. server 执行到accept的时候,阻塞了,等待client的连接
3. client执行connect的时候,client发起三次握手
tcpdump捕捉到三次握手的信息
server accept的阻塞解除,执行到下一行
4. client继续执行,执行完send函数的时候, 发生了client到server的数据交互
5. server继续执行,执行recv的时候,从内核缓存中取出client发过来的数据(tcpdump并没有变化可以看出是在缓存中接收)
6. server继续执行,执行完send函数发消息给client的时候,tcpdump捕捉到server到client的数据交互
7. server继续执行,执行到close(client_fd)的时候,tcpdump捕捉到断开的握手信息
网络状态变为
8. 此时, 关闭了server -> client方向的数据流
9. client继续执行,执行完recv函数,获取到server发送过来的数据(依然从缓存中得到)
10. client运行完close(client_fd)函数, 发起断开握手
11. 网络状态变成
