网络通信手段的一种,我们在之前学了进程间通信,包括管道、消息队列、共享内存、信号和信号量,这些通信方式有一个共同的特点,就是他们都是在依赖Linux内核在单机上进行进程的通信,而面对多机之间的通信,这些手段就远远不够了。所以我们引入网络,利用网络来实现多机之间的通信。
多机通信有好多例子,比如Linux服务器和Adroid、 IOS、C51、x86的Linux之间的通信。 既然谈到网络编程,就一定需要地址,包括IP地址和端口号。IP地址用来标识一台设备,端口号用来标识一台设备上的进程。除了这个,还需要协议来作为支撑,包括TCP、UDP和HTTP协议等,协议作为一种规则,约定了通信双方的数据格式,就好比两个人必须都用中文才能听懂对方说话。
我们在这里主要用到的是Socket网络编程,也叫套接字网络编程,主要用到TCP和UDP协议。
1、TCP面向连接(如打电话要先拨号建立连接) ;UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多, 多对一和多对多的交互通信
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等。
这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP 地址与网络服务的关系是一对多的关系。
实际上是通过“IP地址+端口号”来区 分不同的服务的。端口提供了一种访问通道,服务器一般都是通过知名端口号来识别的。例如,对于每个TCP/IP实现来说,FTP服务器的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69。3000以下的端口号一般是操作系统所使用的,用户一般使用5000到9000的端口号。
字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
字节序分为小端字节序和大端字节序:
TCP/IP协议规定,网络数据流应采用大端字节序
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换:
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
//h表示host,n表示network,l表示32位长整数,s表示16位短整数。
//如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。
注意,网络字节序指的是大端字节序。
1. 创建套接字—socket()
2. 为套接字添加信息(IP地址和端口号)—bind()
3. 监听网络连接—listen()
4. 监听到有客户端接入,接受一个连接—accept()
5. 数据交互
6. 关闭套接字,断开连接
int socket(int domain, int type, int protocol);
(1)domain:通常是AF_INET,指IPV4因特网域
(2)type:指定socket类型,SOCK_STREAM它使用TCP协议,SOCK_DGRAM使用UDP协议
(3)protocol:0默认选择type对应的协议
创建失败返回-1.
int bind(int sockfd, const struct sockaddr *maddr,socklen_t addrlen);
(1)sockfd:网络标识符
(2)struct sockaddr_in{
sa_family_t sin_family; //指定AF_***,表示使用什么协议族的ip格式
in_port_in sin_port; //设置端口号
struct in_addr sin_addr; //设置ip
unsigned char sin_zero[8];
};
(3)结构体大小
其中:struct in_addr sin_addr; //设置ip
中struct in_addr结构体:
把字符串形式的“192.168.1.123”转为网络能识别的格式:
int inet_aton(const char* straddr,struct in_addr *addrp);
网络格式的ip地址转为字符串形式:
char* inet_ntoa(struct in_addr inaddr);
int listen(int sockfd,int backlog)
(1)sockfd:网络连接号
(2)backlog:指定请求队列中同时最大请求数
int accept(int sockfd,struct sockaddr *addr,socklen_t addrlen)
(1)网络连接号
(2)客户端地址,NULL
(3)客户端地址长度,NULL(指针) 返回值是新建立的通道。
connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen)
(1)目的服务器端口号
(2)服务器的IP地址和端口号的结构体
(3)地址长度
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main()
{
int s_fd;
//1.socket
//int socket(int domain, int type, int protocol);
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd == -1){
perror("socket");
exit(-1);
}
struct sockaddr_in s_addr;
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(8989);
//int inet_aton(const char* straddr,struct in_addr *addrp);
inet_aton("192.168.239.135",&s_addr.sin_addr);//ben ji
//2.bind
//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
//int listen(int sockfd, int backlog);
listen(s_fd,10);
//4.accept
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int c_fd = accept(s_fd,NULL,NULL);
//5.read
//6.write
printf("connect!\n");
while(1);
return 0;
}
其中: inet_aton("192.168.239.135",&s_addr.sin_addr);
中的192.168.239.135–另开端口使用指令查询:ifconfig
使用window的命令行窗口telnet 192.168.239.135 8989
已经成功连接!!!
//server.c
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//int socket(int domain, int type, int protocol);
//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int main()
{
int s_fd;
int n_read;
char readBuf[128];
char *msg = "I get your message";
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
//1.创建套接字---socket()
s_fd = socket(AF_INET, SOCK_STREAM,0);
if(s_fd == -1){
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;//
s_addr.sin_port = htons(8988);//转换大端字节序 //8988端口号
inet_aton("192.168.3.250",&s_addr.sin_addr);//字符串格式转换为网络格式
//2.bind
//2.为套接字添加信息(IP地址和端口号)---bind()
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3. listen
//3.监听网络连接---listen()
listen(s_fd,10);//监听
//4.accept
//4.监听到有客户端接入,接受一个连接---accept()
int clen = sizeof(struct sockaddr_in);
int c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);//
if(c_fd == -1){
perror("accept");
}
printf("get connect :%s\n",inet_ntoa(c_addr.sin_addr));//网络格式转换为字符串格式
//5.read
//5.数据交互
n_read = read(c_fd,readBuf,128);
if(n_read == -1 ){
perror("read");
}else{
printf("get message:%d,%s\n",n_read,readBuf);
}
//6.write
//数据交互
write(c_fd,msg,strlen(msg));
return 0;
}
运行结果:
//client.c
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
int c_fd;
int n_read;
char readBuf[128];
char *msg = "message from client";
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
c_fd = socket(AF_INET, SOCK_STREAM,0);
if(c_fd == -1){
perror("socket");
exit(-1);
}
c_addr.sin_family = AF_INET;//
c_addr.sin_port = htons(8988);//zhuanhua daduanzijiexu //duankouhao
inet_aton("192.168.3.250",&c_addr.sin_addr);
//2.connect
if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){
perror("connect");
exit(-1);
}
//3.send
write(c_fd,msg,strlen(msg));
//4.read
n_read = read(c_fd,readBuf,128);
if(n_read == -1 ){
perror("read");
}else{
printf("get message from :%d,%s\n",n_read,readBuf);
}
return 0;
}
//与server.c相互配合
首先实现服务器不退出操作
############################## serve.c ##################################
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int s_fd;
int c_fd;
int n_read;
char readBuf[128];
char *msg = "I get your message!";
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
//int socket(int domain, int type, int protocol);
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd == -1){
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
//int inet_aton(const char* straddr,struct in_addr *addrp);
inet_aton(argv[1],&s_addr.sin_addr);//ben ji
//2.bind
//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
//int listen(int sockfd, int backlog);
listen(s_fd,10);
//4.accept
int clen = sizeof(struct sockaddr_in);
while(1){
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
if(c_fd == -1){
perror("accept");
}
//char* inet_ntoa(struct in_addr inaddr);
printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));
if(fork() == 0){
//5.read
//ssize_t read(int fd, void *buf, size_t count);
n_read = read(c_fd,readBuf,128);
if(n_read == -1){
perror("read");
}else{
printf("get message:%d,%s\n",n_read,readBuf);
}
//6.write
//ssize_t write(int fd, const void *buf, size_t count);
write(c_fd,msg,strlen(msg));
break;
}
}
return 0;
}
################################### client.c ####################################
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int c_fd;
int n_read;
char readBuf[128];
char *msg = "msg from client!";
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
//int socket(int domain, int type, int protocol);
c_fd = socket(AF_INET,SOCK_STREAM,0);
if(c_fd == -1){
perror("socket");
exit(-1);
}
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(atoi(argv[2]));
//int inet_aton(const char* straddr,struct in_addr *addrp);
inet_aton(argv[1],&c_addr.sin_addr);//ben ji
//2.connect
//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1){
perror("connect");
exit(-1);
}
//3.send
//ssize_t write(int fd, const void *buf, size_t count);
write(c_fd,msg,strlen(msg));
//4.read
//ssize_t read(int fd, void *buf, size_t count);
n_read = read(c_fd,readBuf,128);
if(n_read == -1){
perror("read");
}else{
printf("get message from server:%d,%s\n",n_read,readBuf);
}
printf("connect!\n");
return 0;
}
可见,服务端一直不退出,一直在接受消息!!!
//server.c
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//int socket(int domain, int type, int protocol);
//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int main(int argc,char **argv)
{
int s_fd;
int c_fd;
int n_read;
char readBuf[128];
// char *msg = "I get your message";
char msg[128] = {
0};
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
if(argc != 3){
printf("param is not good\n");
exit(-1);
}
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
s_fd = socket(AF_INET, SOCK_STREAM,0);
if(s_fd == -1){
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;//
s_addr.sin_port = htons(atoi(argv[2]));//zhuanhua daduanzijiexu //duankouhao
inet_aton(argv[1],&s_addr.sin_addr);
//2.bind
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3. listen
listen(s_fd,10);//jianting 10ge
//4.accept
int clen = sizeof(struct sockaddr_in);
while(1){
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);//
if(c_fd == -1){
perror("accept");
}
printf("get connect :%s\n",inet_ntoa(c_addr.sin_addr));//wangluo zhaunhua zifuchuan
if(fork() == 0){
//zijincheng
if(fork() == 0){
while(1){
memset(msg,0,sizeof(msg));
printf("input: ");
gets(msg);
//6.write
write(c_fd,msg,strlen(msg));
}
}
//5.read
while(1){
memset(readBuf,0,sizeof(readBuf));
n_read = read(c_fd,readBuf,128);
if(n_read == -1 ){
perror("read");
}else{
printf("get message:%d,%s\n",n_read,readBuf);
}
}
break;
}
}
return 0;
}
//client.c
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//int socket(int domain, int type, int protocol);
//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int main(int argc,char **argv)
{
int c_fd;
int n_read;
char readBuf[128];
// char *msg = "message from client";
char msg[128] = {
0};
struct sockaddr_in c_addr;
if(argc != 3){
printf("param is not good\n");
exit(-1);
}
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
c_fd = socket(AF_INET, SOCK_STREAM,0);
if(c_fd == -1){
perror("socket");
exit(-1);
}
c_addr.sin_family = AF_INET;//
c_addr.sin_port = htons(atoi(argv[2]));//zhuanhua daduanzijiexu //duankouhao
inet_aton(argv[1],&c_addr.sin_addr);
//2.connect
if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){
perror("connect");
exit(-1);
}
while(1){
if(fork() == 0 ){
while(1){
memset(msg,0,sizeof(msg));
printf("input: ");
gets(msg);
//3.send
write(c_fd,msg,strlen(msg));
}
}
while(1){
memset(readBuf,0,sizeof(readBuf));
//4.read
n_read = read(c_fd,readBuf,128);
if(n_read == -1 ){
perror("read");
}else{
printf("get message from :%d,%s\n",n_read,readBuf);
}
}
}
return 0;
}
双方开始沟通交流!!!
实现了服务端和客户端双方的聊天,但是我们遇到一个问题,就是当我们多开一个客户端的时候,客户端可以给服务端发消息,但是服务端给客户端发消息的时候,就会产生不确定的情况。就是当有多个客户端访问服务端的时候,服务端不知道把消息发送给谁,其无法解决精准的一对一的通信问题,经过一番研究发现,其实不是因为服务端无法对接客户端进程的问题,而是因为服务端输入发送内容时的光标无法解析发给谁的问题,下面对服务端代码做了一些改进,验证了能够实现服务端和客户端能够一对一精准通信的问题。
//server.c
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//int socket(int domain, int type, int protocol);
//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int main(int argc,char **argv)
{
int s_fd;
int c_fd;
int n_read;
char readBuf[128];
int mark = 0;
// char *msg = "I get your message";
char msg[128] = {
0};
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
if(argc != 3){
printf("param is not good\n");
exit(-1);
}
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
s_fd = socket(AF_INET, SOCK_STREAM,0);
if(s_fd == -1){
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;//
s_addr.sin_port = htons(atoi(argv[2]));//zhuanhua daduanzijiexu //duankouhao
inet_aton(argv[1],&s_addr.sin_addr);
//2.bind
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3. listen
listen(s_fd,10);//jianting 10ge
//4.accept
int clen = sizeof(struct sockaddr_in);
while(1){
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);//
if(c_fd == -1){
perror("accept");
}
mark ++;
printf("get connect :%s\n",inet_ntoa(c_addr.sin_addr));//wangluo zhaunhua zifuchuan
if(fork() == 0){
//zijincheng
if(fork() == 0){
while(1){
memset(msg,0,sizeof(msg));
sprintf(msg,"Welcome NO.%d client",mark);
//6.write
write(c_fd,msg,strlen(msg));
sleep(3);
}
}
//5.read
while(1){
memset(readBuf,0,sizeof(readBuf));
n_read = read(c_fd,readBuf,128);
if(n_read == -1 ){
perror("read");
}else{
printf("get message:%d,%s\n",n_read,readBuf);
}
}
break;
}
}
return 0;
}
客户端:
1.获取服务器文件 get xxx 功能2.0
2.展示服务器有哪些文件 ls 功能1.0
3.进入服务器文件夹 cd xx 功能3.0
4.上传文件到服务器 put xx 功能4.0
本地:
1.lls 查看客户端本地文件 功能5.0
2.lcd 进入客户端文件夹 功能5.0
文章浏览阅读857次。CentOS上部署Java项目开发环境CentOS上负责分发程序的yum命令。Ⅰ 安装软件的常用下载工具(1)yum的基本使用1)查看软件包列表(完整名称)yum list | grep [关键字]2)安装软件包 yum install [软件包完整名称]3)卸载软件包yum remove [软件包完整名称](2)wgetwget http://...hellp.zip -O down.zip(3) curlcurl 'http://...hellp.zip' -O down.zip_centos 7 部署java
文章浏览阅读350次。选择排序_leetcode选择排序题目java
文章浏览阅读3.2k次,点赞2次,收藏2次。历史AAM的思想最早可以追溯到1987年kass等人提出的snake方法,主要用于边界检定与图像分割。该方法用一条由n个控制点组成的连续闭合曲线作为snake模型,再用一个能量函数作为匹配度的评价函数,首先将模型设定在目标对象预估位置的周围,再通过不断迭代使能量函数最小化,当内外能量达到平衡时即得到目标对象的边界与特征。 1989年yuille等人此提出使用参数化的可变形模板来代替snak_opencv 主动外观模型
文章浏览阅读241次。Mapper.xml 配置Mapper.xml 配置call pro_emp(#{emps,mode=OUT,jdbcType=CURSOR,javaType=java.sql.ResultSet,resultMap=empMap}) ]]>存储过程:create or replace procedure pro_emp(cur_sys out sys_refcursor)asbegino..._mybatis oracle存储过程 public void setparameter(
文章浏览阅读206次。python毕业设计作品基于django框架 疫苗预约系统毕设成品(3)后台管理功能
文章浏览阅读185次。分割等和子集_分割等和子集
文章浏览阅读1.2k次,点赞3次,收藏2次。Hello!ଘ(੭ˊᵕˋ)੭昵称:海轰标签:程序猿|C++选手|学生简介:因C语言结识编程,随后转入计算机专业,获得过国家奖学金,有幸在竞赛中拿过一些国奖、省奖…已保研学习经验:扎实基础 + 多做笔记 + 多敲代码 + 多思考 + 学好英语!唯有努力。
文章浏览阅读606次。Flink一、Flink 简介 Apache Flink是一个 框架 和 分布式处理引擎,用于对 无界 和 有界 数据流进行 有状态计算。1.1 Flink 的特点事件驱动型(event-driven)事件驱动型应用是一类具有状态的应用,它从一个或多个事件流提取数据,并根据到来的事件触发计算、状态更新或其他外部动作。比较典型的就是以 kafka 为代表的消息队列几乎都是事件驱动型应..._flink parameter index out of range 9 > number of parameters, which is
文章浏览阅读9.3k次,点赞11次,收藏49次。1.零件的分类零件是组成机器和部件最小单元,按照一定装配关系组合形成部件和机器。根据零件的作用及其结构,通常分为以下几类:2.零件图的作用与内容1、零件图:表达零件结构、大小及技术要求的图样。2、零件图作用:是制造和检测零件质量的依据,它直接服务于生产,是生产中的重要技术文件。3、零件图内容:零件图不仅要反映设计者的设计意图,而且要表达零件的各种技术要求,如:尺寸精度、表面粗糙度等。完整的零件图应具备:一组视图、完整的尺寸、技术要求和标题栏。(1)一组视图选择适当的剖视、断._机械制图图样代号
文章浏览阅读2.4k次。苹果MAC笔记本外接显示器设置方法/步骤:1、如果要在 Mac 上外接显示器的话,首先是要考虑采用什么样的接口。一般我们是通过 VGA 或 HDMI 来外接显示器的。如果 Mac 电脑上没有可以外接显示器的 VGA 或 HDMI 接口的话,就只有选择用 USB 或其它接口的转接器了。下图是苹果官网的一张 USB 转接 HDMI 线缆。2、根据自己电脑和显示器的情况,考虑采用何种外接接口。比如我的 ..._macbook 设置外接显示器扩展
文章浏览阅读581次。VUE-SSR 第一次改造方案(二)_vite vue3 已有项目改造ssr
文章浏览阅读1k次。上面创建的是yoyoketang分支,pycharm默认会切换到yoyoketang分支。创建分支可以快速的回滚到某个节点的版本,也可以多个开发者同时开发一个项目,当自己的功能完成后,提交到自己的分支上。当我们写的项目代码越来越多时,一个master分支无法满足需求了,这个时候就需要创建分支来管理代码。上面分支创建成功后,pycharm所在的分支就是当前的新建分支上了。推送成功后,查看代码仓库,yoyoketang分支创建成功。在分支上测试通过后,最后把代码合并到master分支。自己随便写个分支名称。_pycharm推送分支