Linux 网络 tcp C/S通信模型
C/S模型就是server 与 client 的模型
TCP服务器模型流程图 TCP 客户端模型流程图:
函数使用:
(1)创建一个网络通信套接字描述符 int socket(int domain, int type, int protocol);
参数:domain : 协议系列,常用的是 AF_INET 表示IPV4
type : 常用的两个
SOCK_STREAM 流式套接字 TCP 常用
SOCK_DGRAM 数据报套接字 UDP 常用
protocol:一般为0
返回值:通信过程中使用的socket(一个文件描述符)
(2)把socket与 ip, 端口绑定一起 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数 :sockfd :通过socket 函数创建返回的通信文件描述符
addr:addr 是指向 sockaddr_in 结构的指针,包含本机IP 地址和端口号协议类型等
addrlen: addrLen : sizeof (struct sockaddr_in) 是第二个参数addr结构所占的有效长度
struct sockaddr结构 和 struct sockaddr_in结构
struct sockaddr {
sa_family_t sa_family; //协议族
char sa_data[]; // 14字节协议地址
} struct sockaddr_in{
u_short sin_family;// 地址族, AF_INET,2 bytes
u_short sin_port; // 端口,2 bytes
struct in_addr sin_addr; // IPV4地址结构,4 bytes
char sin_zero[]; // 8 bytes unused,作为填充
};
在bind时使用 struct sockaddr_in 结构进行初始化,然后通过 struct sockaddr 强制类型转换
sockaddr_in 与 sockaddr 结构的区别
(3) 监听绑定了ip和port的socket :int listen(int sockfd, int backlog);
参数:sockfd:监听连接的套接字
backlog 指定了完全成功连接的最大队列长度,它的作用在于处理可能同时出现的几个连接请求。此参数现在基本已经不用。
返回值: 0 或 -1
完成listen()调用后,socket变成了监听
(4)阻塞等待连接 :int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数: sockfd : 监听套接字
addr : 对方地址
addrlen:地址长度
返回值:已建立好连接的套接字 或 -1
(5) 发送数据
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
参数: sockfd :向哪个socket发送数据
buf :存放数据缓存首地址
len :发送的数据长度
flags:发送方式(通常为0)
返回值:成功:实际发送的字节数 失败:-1, 并设置errno
(6) 接收数据
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数:socket:向哪个socket发送数据
buf : 发送缓冲区首地址
length : 发送的字节数
flags : 接收方式(通常为0)
返回值: 成功:实际接收的字节数 失败:-1, 并设置errno
(7) 客户端连接服务器的函数
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数:sockfd : socket返回的文件描述符
serv_addr : 服务器端的地址信息
addrlen : serv_addr的长度
返回值:0 或 -1
(8) 关闭通信socket int close(int fd);
编写TCP 的server和client 通信程序,服务器监听接收数据
server.c文件:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <strings.h> #define MAX_BUF 1024
int main(int argc, const char *argv[])
{
char buf[MAX_BUF] = {};//接收数据缓存
int server_sock_fd; //服务器,socket描述符
int client_sock_fd; //链接的客户端,socket 描述符
ssize_t tybes; struct sockaddr_in server_addr;//存放服务器ip和端口
struct sockaddr_in client_addr;//存放客户端ip和端口
socklen_t len; len = sizeof(server_addr);
bzero(&server_addr,len);//清零
server_sock_fd = socket(AF_INET, SOCK_STREAM,);//创建socket,返回socket描述符
if(server_sock_fd < )
{
perror("socket fail ");
exit();
} //填充 地址和端口结构
server_addr.sin_family = AF_INET; //协议族
// server_addr.sin_port = htons(atoi(argv[2])); //服务器端口 //这两行是通过执行程序时传入参数ip和port
// server_addr.sin_addr.s_addr = inet_addr(argv[1]);//IP地址
server_addr.sin_port = htons(atoi("")); //服务器端口 , htons 把主机字节序转为网络字节序,atoi 把字符数据转为整数
server_addr.sin_addr.s_addr = inet_addr("192.168.3.132");//IP地址 ,inet_addr把字符串ip转为网络字节序整数
if(bind(server_sock_fd, (struct sockaddr*)&server_addr, len) < ) //绑定服务器 ip和port
{
perror("fail bind ");
exit();
} if( listen(server_sock_fd,) < ) //监听 服务器
{
perror("fail listen ");
exit();
} while()
{
client_sock_fd = accept(server_sock_fd,(struct sockaddr*)&client_addr,&len);//阻塞等待客户端链接
if(client_sock_fd < )
{
perror("client socket fail ");
exit();
}
printf("client ip %s port %u\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port)); //打印链接的ip 和 port
while()
{
memset(buf,,);
// tybes = recv(client_sock_fd,buf,10,0);
tybes = read(client_sock_fd,buf,);
if(tybes <= ) //断开链接或者出错
{
puts("recv error !");
break;
}
printf("recv data : %s",buf);//IO缓冲 加 换行输出
if(strstr(buf,"quit") != NULL ) //接收到 “quit” 断开连接的客户端,等待下一个连接
{
close(client_sock_fd);
break;
}
} }
close(server_sock_fd);
return ;
}
client.c 文件;
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h> int main(int argc, const char *argv[])
{
int client_sock_fd;
char buf[] = {};
ssize_t send_tybes;
struct sockaddr_in server_addr;
socklen_t len;
len = sizeof(server_addr);
bzero(&server_addr,len); //清零 client_sock_fd = socket(AF_INET,SOCK_STREAM,); //创建客户端 socket
if(client_sock_fd < )
{
perror("client_sock_fd fail ");
exit();
} //填充服务器 地址
server_addr.sin_family = AF_INET;
// server_addr.sin_port = htons(atoi(argv[2]));
// server_addr.sin_addr.s_addr = (inet_addr(argv[1]));
server_addr.sin_port = htons(atoi(""));
server_addr.sin_addr.s_addr = (inet_addr("192.168.3.132")); if( connect(client_sock_fd, (struct sockaddr*)&server_addr, len) < ) //连接服务器
{
perror("connect fail ");
exit();
} while()
{
fgets(buf,,stdin); //终端读取数据
send_tybes = send(client_sock_fd,buf,,);
if(send_tybes <= ) //接收数据失败或者断开连接
{
printf("send fail !");
break;
}
if(strstr(buf,"quit") != NULL) //输入 “quit” 断开连接
{
break;
}
}
close(client_sock_fd);
return ;
}
测试:此时,服务器只是接收数据,不能发送数据,因为接收和终端获取数据是两个阻塞函数,需要开启多进程或者多线程处理两个阻塞问题
Linux 网络 tcp C/S通信模型的更多相关文章
- Linux下TCP网络编程与基于Windows下C#socket编程间通信
一.linux下TCP网络编程基础,需要了解相关函数 Socket():用于套接字初始化. Bind():将 socket 与本机上的一个端口绑定,就可以在该端口监听服务请求. Listen():使s ...
- 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
[Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...
- Linux网络编程:基于TCP的程序开发回顾篇《转》
面向连接的TCP程序设计 基于TCP的程序开发分为服务器端和客户端两部分,常见的核心步骤和流程: 其实按照上面这个流程调用系统API确实可以完全实现应用层程序的开发,一点问题没有.可随着时间的推移,你 ...
- Linux网络IO函数以及TCP连接函数包装
标准I/O VS 网络IO 标准I/O又称为标准I/O流,从某种意义上讲是全双工的,因为程序能够在同一个流上执行输入和输出. Unix/Linux对网络的抽象是一种称为套接字的文件类型.和任何Unix ...
- Linux网络编程——tcp并发服务器(poll实现)
想详细彻底地了解poll或看懂下面的代码请参考<Linux网络编程——I/O复用之poll函数> 代码: #include <string.h> #include <st ...
- TCP/UDP Linux网络编程详解
本文主要记录TCP/UDP网络编程的基础知识,采用TCP/UDP实现宿主机和目标机之间的网络通信. 内容目录 1. 目标2.Linux网络编程基础2.1 嵌套字2.2 端口2.3 网络地址2.3.1 ...
- 基于Linux的TCP网络聊天室
1.实验项目名称:基于Linux的TCP网络聊天室 2.实验目的:通过TCP完成多用户群聊和私聊功能. 3.实验过程: 通过socket建立用户连接并传送用户输入的信息,分别来写客户端和服务器端,利用 ...
- Linux网络编程一、tcp三次握手,四次挥手
一.TCP报文格式 (图片来源网络) SYN:请求建立连接标志位 ACK:应答标志位 FIN:断开连接标志位 二.三次握手,数据传输,四次挥手 (流程图,图片来源于网络) (tcp状态转换图,图片来源 ...
- Linux网络驱动--snull
snull是<Linux Device Drivers>中的一个网络驱动的例子.这里引用这个例子学习Linux网络驱动. 因为snull的源码,网上已经更新到适合最新内核,而我自己用的还是 ...
随机推荐
- python_ 模块 json pickle shelve
一,什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用python编写的代码( ...
- UVALive 4794 Sharing Chocolate
Sharing Chocolate Chocolate in its many forms is enjoyed by millions of people around the world ever ...
- React 16.4 生命周期
补一下 React 16.4版本的生命周期图
- teb教程9
通过costmap_converter来跟踪和包含动态障碍物 简介:利用costmap_converter来很容易跟踪动态障碍物 1.costmap_converter中提供了一个插件称之为costm ...
- 【转载】sublime text3 全攻略
给个链接:http://www.w3cfuns.com/blog-5466732-5405668.html 等作者更新完后自己再整理
- Go: Println 与 Printf 的区别
Go 学习笔记:Println 与 Printf 的区别,以及 Printf 的详细用法 2017-12-19 15:39:05 zgh0711 阅读数 26255更多 分类专栏: Go 版权声明 ...
- hibernate3.6异常
WARN DTDEntityResolver:73 - recognized obsolete hibernate namespace http://hibernate.sourceforge.net ...
- Java——异常的基本概念
1.异常的基本概念 1.1什么是异常 在使用计算机语言进行项目开发的过程中,即使程序员把代码写得尽善尽美,在系统的运行过程中仍然会遇到一些问题,因为很多问题不是靠代码能够避免的,比如:客户输入数据的格 ...
- Java——面向对象知识总结
面向对象的三条主线: 一.类及类的成分 1.类与类的关系: java程序是关注于类的设计. 类从代码的角度:并列关系! 从执行.设计的角度:关联关系.继承关系.聚合关系 class A{ } clas ...
- 浅析阿里云API网关的产品架构和常见应用场景
自上世纪60年代计算机网络发展开始,API(Application Programming Interface )随之诞生,API即应用程序接口,是实现系统间衔接的桥梁.时至今日,API市场已经形成了 ...