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的源码,网上已经更新到适合最新内核,而我自己用的还是 ...
随机推荐
- android中SharedPreferences
SharedPreferences:用于存储少量并且数据格式简单,基本上都是普通的字符串,标量类型的值,比如:应用程序的各种配置信息等. SharedPreferences:保存的数据格式主要是key ...
- 【牛客网-剑指offer】变态跳台阶
题目: 一只青蛙一次可以跳上1级台阶,也可以跳上2级--它也可以跳上n级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 考点: 递归和循环 分析: 台阶数 跳法 1 1 2 2 3 4 4 8 5 1 ...
- Draggable(拖动框)
一.class加载方式 <div id="box" class="easyui-draggable" style="width:400px;he ...
- 解决code first Migration 增加外键时出现错误的问题
先上模型 Comment public class Comment { [Key] public int CommentId { get; set; } [Required] public int S ...
- ASE: CODEnn Reproduce
Background 第二次结对编程的任务是挑选一个用自然语言搜索相关代码片段的模型实现,并且可以提出自己的想法改进.这个任务很cool,前期做了不少调研.使用自然语言搜索相关代码片段现在是个很受关注 ...
- codeforces1213F Unstable String Sort 思维
题目传送门 题意:a和b都代表字符串的下标,至少用k个字符,构造一个长度为n的字符串,将这个字符串中的字符按无论是按$a$写还是按$b$写,字典序都非递减. 思路:如果将$a[l,r]=b[l,r]$ ...
- html浮动小问题
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- java程序中的多线程(转)
为什么会排队等待? 下面的这个简单的 Java 程序完成四项不相关的任务.这样的程序有单个控制线程,控制在这四个任务之间线性地移动.此外,因为所需的资源 ― 打印机.磁盘.数据库和显示屏 -- 由于硬 ...
- Map集合类(一.hashMap源码解析jdk1.8)
java集合笔记一 java集合笔记二 java集合笔记三 jdk 8 之前,其内部是由数组+链表来实现的,而 jdk 8 对于链表长度超过 8 的链表将转储为红黑树 1.属性 //节点数组,第一次使 ...
- springboot集成使用rabbitmq笔记(2.rabbitmq使用)
使用rabbitmq笔记一 使用rabbitmq笔记二 使用rabbitmq笔记三 1.引入包 <dependencies> <dependency> <groupId& ...