通信流程
服务端
- socket()—>创建套接字(用于监听)
- bind()------>绑定地址结构
- listen()----->设置最大监听套接字数量
- accept()---->阻塞等待客户端连接(返回一个新的套接字用于通信)
- read()------->读取数据
- foo()--------->处理数据
- write()------->写回数据
- close()------->返回第5步或结束通信
客户端
- socket()——>创建套接字(用于通信)
- connect()---->连接服务端
- write()-------->发送数据
- read()--------->接受数据
- close()------->返回第4步或结束通信
一些小问题
-
Q: 需要创建多少个套接字:
A: 至少需要三个套接字,其中一个用于监听,两个分别用于客户端和服务器的通信 -
Q:为什么客户端没有bind():
A: 客户端当然也可以绑定struct sockaddr_in地址结构,没有绑定时,系统会自动分配空闲的地址结构 -
IP地址调用ifconfig来查看,替换代码中的,端口号同样可以自定义
-
accept()返回时其实就是三次握手完成时,关结束通信时完成四次挥手,不过这些事情操作系统会帮我们完成,网络分层模型的上一层只要学会使用下一层提供的接口,不必在意下一层如何实现,网络编程一系列函数其实就是系统针对TCP协议提供的一些接口函数
服务端代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <pthread.h>
#include <ctype.h>
#define SERV_PORT 9527
void my_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
int listen_fd, connect_fd;
char buf[BUFSIZ], client_ip[1024];
struct sockaddr_in server_addr, client_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERV_PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
socklen_t len_client = sizeof(client_addr);
//创建套接字(用于监听)
if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
my_err("socket error");
}
//绑定地址结构(IP & port)
if (bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
{
my_err("bind error");
}
//设置最大监听客户端数量
if (listen(listen_fd, 128) == -1)
{
my_err("listen error");
}
//阻塞等待客户端响应
if ((connect_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &len_client)) == -1)
{
my_err("accept error");
}
//打印客户端信息
printf("client : ip = %s, port = %d\n",
inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, client_ip, sizeof(client_ip)),
ntohs(client_addr.sin_port));
while (1)
{
int ret = read(connect_fd, buf, sizeof(buf));
write(STDOUT_FILENO, buf, ret);
for (int i = 0; i < ret; i++)
{
buf[i] = toupper(buf[i]);
}
//printf("ret = %d\n", ret);
write(connect_fd, buf, ret);
}
close(listen_fd);
close(connect_fd);
return 0;
}
客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <pthread.h>
#define SERV_PORT 9527
void my_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
int connect_fd;
char buf[BUFSIZ];
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, "172.17.0.1", &server_addr.sin_addr.s_addr);
if ( (connect_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
my_err("socket error");
}
//将套接字和客户端建立连接
if (connect(connect_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
{
my_err("connect error");
}
while (1)
{
write(connect_fd, "hello\n", 6);
sleep(2);
int ret = read(connect_fd, buf, sizeof(buf));
//printf("ret = %d\n", ret);
write(STDOUT_FILENO, buf, ret);
}
close(connect_fd);
return 0;
}