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的源码,网上已经更新到适合最新内核,而我自己用的还是 ...
随机推荐
- enovia plm export to sap
UPC creation UPC 结构 PLM 使用的UPC 是 14个数字组成的,兼容. 前两位为 0,后12位为有效数字,在SAP中0会被忽略,符合国际UPC通用 规则, 前一位为0,后13 位为 ...
- easyui grid单元格类型
在实际应用中可能会碰到不同的需求,比如会根据每行不同的参数或属性设置来设置同列不同的editor类型,这时原有的例子就显的有点太过简单,不能实现我们的需求,现在应用我在项目中的操作为例,显示下实现同列 ...
- Ansible 和 Playbook 暂存
Ansible 和 Playbook 暂存 , 也是一个批量管理工具 自动化的批量管理工具 主机清单 HOST Inventory 模块插件 Playbooks 查看ansible的目录结构 ...
- Android 使用android-support-multidex解决Dex超出方法数的限制问题,让你的应用不再爆棚(转)
如有转载,请声明出处: 时之沙: http://blog.csdn.net/t12x3456 (来自时之沙的csdn博客) 随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sd ...
- 【LeetCode】Stack
[503] Next Greater Element II [Medium] 给一个循环数组,找到离当前元素最近的比它大的元素. Input: [1,2,1] Output: [2,-1,2] Exp ...
- Tomcat 在IE中下载rar文件直接以乱码方式打开解决方案
这几天一直很纳闷,在Tomcat部署的网站中的下载文件中,如果文件是rar类型的,一点击下载rar文件就直接打开,并且出现乱码,右键另存为浏览器也是默认为html格式,一直以为是浏览器IE的问题,后来 ...
- Java异常架构与异常关键字
Java异常简介 Java异常是Java提供的一种识别及响应错误的一致性机制. Java异常机制可以使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并提高程序健壮性.在有效使用异常的情况 ...
- Docker 初识之路
一. 安装配置 1.安装依赖 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 2.设置阿里云镜像源 sudo yu ...
- 【多线程】volatile
Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...
- XCode文件状态为 ? 解决办法(git)
XCode文件状态为 ?,意思为不识别的文件类型. 解决办法: