前言
在初入tcp通信时,深感调用头文件与函数之多,难以记住。本文目的旨在提炼出一个框架(里面包含很多模块),针对每个模块,自己实现的时候可以去百度查找对应对函数即可。
https://download.csdn.net/download/m0_62128864/57140157?utm_medium=distribute.pc_relevant_download.none-task-download-2defaultBlogCommendFromBaiduRate-1-57140157-download-13094046.pc_relevant_download_topnsimilarv2&depth_1-utm_source=distribute.pc_relevant_download.none-task-download-2defaultBlogCommendFromBaiduRate-1-57140157-download-13094046.pc_relevant_download_topnsimilarv2&dest=https%3A%2F%2Fdownload.csdn.net%2Fdownload%2Fm0_62128864%2F57140157&spm=1003.2020.3001.6616.1
客户端
- 客户端创建套接字fd1;
- 客户端client1通过套接字fd1连接服务器的listen_fd;
代码框架如下
int main()
{
% 创建socket
socket();
% 创建本地地址结构体
struct sockaddr_in;
% 根据socket,地址结构体,连接服务器
connect()
%循环收发消息
收发对应的缓存数组
while(1)
{
}
}
并发服务器端_实现1:
3.关于服务器端两个socket的解释
可参考文章:为什么有监听socket和连接socket,为什么产生两个socket
从5中的描述上可以看出,accpet生成一个新的socket连接,返回该socket的文件描述符。对服务端来说,有两个socket,一个是用于监听的socket,还有一个就是客户端连接成功后,由accept函数创建的用于与客户端收发报文的socket。我觉得上面的文章总结的很到位:职责分工, 分层协作, 提高服务端性能。
记得一个很隐晦错误的知识点:
从0实现基于Linux socket聊天室-多线程服务器一个很隐晦的错误-2
开一个循环,在循环中 对每一个与客户端建立的连接,采用多线程处理。
%线程调用函数
void thread_fun()
{
recv();
send();
}
int main()
{
%创建socket,用于监听客户端请求
socket();
% 创建本地地址结构体,初始化地址和端口
struct sockaddr_in;
%将socket文件描述符绑定到本地地址和端口
bind();
%开始监听该socket
listen();
%循环接收多个客户端请求
while(1)
{
%服务器阻塞,直到服务器接受客户端程序建立连接
%每次accept,都会产生一个新的文件描述符
accept();
%调用多线程进行处理
thread_fun();
}
}
并发服务器端_实现2:
服务端各线程独自accept(),使用互斥锁,使用pthread_create()建立多个线程组成的线程池,主线程等待程序结束,各个线程独自接收客户端accept。
定义互斥锁
%% 建立线程池,处理accept函数
void fun1()
{
%循环创建线程池,获得多个线程id
for()
{
%对每一个线程id,调用多线程处理函数
thread_fun(id);
}
%主线程需要等待子线程执行完成之后再结束,
for()
{
join()
}
}
%线程调用函数
void thread_fun(fd)
{
while(1)
{
加锁
accept();
解锁
recv();
send();
}
}
int main()
{
%创建socket,用于监听客户端请求
socket();
% 创建本地地址结构体,初始化地址和端口
struct sockaddr_in;
%将socket文件描述符绑定到本地地址和端口
bind();
%开始监听该socket
listen();
%创建线程池
fun1();
}