厦门网站建设制作,百度开店怎么收费,建设银行网站首页是多少,长春房产网官网新楼盘TCP协议#xff1a;面向链接#xff0c;面向字节流#xff0c;可靠通信
创建tcp_server
1.创建套接字 域#xff1a;依旧选择AF_INET 连接方式#xff1a; 选择SOCK_STREAM 可靠的
2.bind 3.监听装置
client要通信#xff0c;要先建立连接#xff0…TCP协议面向链接面向字节流可靠通信
创建tcp_server
1.创建套接字 域依旧选择AF_INET 连接方式 选择SOCK_STREAM 可靠的
2.bind 3.监听装置
client要通信要先建立连接client主动建立连接所以服务端要一直等待连接 4.获取连接
成功返回新的sockfd失败返回-1 我们在使用UDP时我们的sockfd一直都是同一个但是在TCP这里我们收到了一个新的sockfd那我们客户端服务端通信的时候是用哪一个socket呢 一个故事:有一家饭店有一个叫张三的员工在外面拉客拉到客后就进入餐馆叫服务员A给顾客A提供服务所以顾客A的所有要求都由服务员A提供。所以我们在通信时用的是返回的新的socket我们创建的socket理论上叫Listensocket 如果失败了返回-1我们得让循环退出吗 不我们的continue让socket持续监听
提供服务 调用read write进行读写 read如果读到了0表示读到了文件结尾表明对端关闭了连接
#pragma once
#include iostream
#include cstring
#include sys/types.h
#include sys/socket.h#include unistd.h
#include errno.h#include netinet/in.h
#include arpa/inet.h#include Log.hpp
#include Comm.hpp
using namespace std;
const int defaultblacklog 5;
class TcpServer
{
public:TcpServer(const uint16_t port) : _port(port){}void Server(int sockfd){while (true){char buff[1024];int n read(sockfd, buff, sizeof(buff) - 1);if (n 0){//读取成功buff[n]0;lg.LogMessage(Info,read success);cout#Client say:buffendl;// string sendbuff;// cout#Please Enterendl;// getline(cin,sendbuff);// int mwrite(sockfd,sendbuff.c_str(),sizeof(sendbuff));// if(m0)// {// lg.LogMessage(Fatal,write failed errno:%d :%s,errno,strerror(errno));// }// lg.LogMessage(Info,Write success.......);}else if(n0){break;lg.LogMessage(Info,Client quit.......);}else{lg.LogMessage(Fatal,read failed errno:%d :%s,errno,strerror(errno));}}}void Init(){// 创建套接字_listensocket socket(AF_INET, SOCK_STREAM, 0);if (_listensocket 0){lg.LogMessage(Fatal, create socket failed errno %d:%s\n, errno, strerror(errno));}lg.LogMessage(Debug, create socket success _socket:%d\n, _listensocket);// bindstruct sockaddr_in addr;bzero(addr,sizeof(addr));addr.sin_family AF_INET;addr.sin_port _port;addr.sin_addr.s_addr INADDR_ANY;int n bind(_listensocket, CONV(addr), sizeof(addr));if (n 0){lg.LogMessage(Fatal, create socket failed errno %d:%s\n, errno, strerror(errno));}lg.LogMessage(Debug, bind socket success _socket:%d\n, _listensocket);// 监听装置int m listen(_listensocket, defaultblacklog);if (m 0){lg.LogMessage(Fatal, listen failed errno %d:%s\n, errno, strerror(errno));}lg.LogMessage(Debug, listen success _socket:%d\n, _listensocket);}void Start(){// 获取连接while (true){struct sockaddr_in peer;socklen_t peerlen sizeof(peer);int wrsockfd accept(_listensocket, CONV(peer), peerlen);if (wrsockfd 0){// 获取连接成功 提供服务Server(wrsockfd);}else{// 获取连接失败 但是一直获取continue;}// 提供服务close(wrsockfd);}}~TcpServer(){}private:uint16_t _port;int _listensocket;
};
netstat -nltp 查看服务器 客户端
1.创建套接字 同sever端 2.建立连接 连接后自动进行bind inet_pton:更安全
#include iostream
#include cstring#include sys/types.h
#include sys/socket.h#include unistd.h
#include errno.h#include netinet/in.h
#include arpa/inet.h#include Log.hpp
#include Comm.hpp
using namespace std;
void Usage(std::string proc)
{std::cout Usage : \n\t proc server_ip server_port\n std::endl;
}
int main(int argc, char *argv[])
{if (argc ! 3){Usage(argv[0]);cerr Usage error endl;exit(Usage_Err);}// 创建套接字int _socket socket(AF_INET, SOCK_STREAM, 0);if (_socket 0){lg.LogMessage(Fatal, create socket failed errno %d:%s\n, errno, strerror(errno));}lg.LogMessage(Debug, create socket success _socket:%d\n, _socket);// 建立连接string serveripargv[1];uint16_t serverportstoi(argv[2]);struct sockaddr_in serveraddr;bzero(serveraddr,sizeof(serveraddr));serveraddr.sin_familyAF_INET;serveraddr.sin_portserverport;if(inet_pton(AF_INET,(serverip.c_str()),serveraddr.sin_addr));int nconnect(_socket,CONV(serveraddr),sizeof(serveraddr));if(n0){lg.LogMessage(Fatal, connect failed errno %d:%s\n, errno, strerror(errno));}lg.LogMessage(Debug, connect success _socket:%d\n, _socket);// 输入信息while(true){string buff;coutPlease Enter:endl;getline(cin,buff);int nwrite(_socket,buff.c_str(),sizeof(buff));}
} main,cc
#include TcpServer.hpp
#include Comm.hpp
#include Daemon.hpp
void Usage(std::string proc)
{std::cout Usage : \n\t proc local_port\n std::endl;
}
int main(int argc,char* argv[])
{if(argc!2){Usage(argv[0]);cerrUsage errorendl;exit(Usage_Err);}uint16_t portstoi(argv[1]);TcpServer *tcpsnew TcpServer(port);tcps-Init();tcps-Start();Daemon(true,false);lg.Enable(ClassFile);
} udp面向数据报和tcp面向字节流有什么区别数据报数据和数据是有边界的 sendto一次对应着recv一次字节流write 一次十次一百次read可能一次就读完也可能几十次但是read端与write端无关 我们编写IO代码尤其是网络IO时我们的read和write是有BUG的
我们的服务器得以后台进程的方式运行真正的服务是以后台进程以守护进程精灵进程的方式运行
守护进程 进程组ID 会话ID 同时启动的进程可以是一个进程组的进程组id通常是其中的某一个进程的pid
每次我们登入linux-OS默认提供1.bash2.提供一个终端-给用户提供命令解释的服务-叫做一个会话组在一个命令行启动的所有进程最终都是这个会话内的一个进程组。
会话内的进程组任何时候一个会话内部存在很多个进程组但是默认法人和时刻只允许一个进程组在前台前台进程组。
前台进程可以接受IO的是前台进程、
jobs查看 fg task_number 前台 ctrlZ bg task_number 后台 或者进程
守护进程自己是一个独立的会话他不属于任何的bash会话。 谁启动setsid谁就是会话的所属进程。 调用setsid的进程不能是组长启动多个进程时第一个启动进程就是组长启动一个进程时这个进程就是组长 所以我们一般要创建子进程让父进程直接退出所以守护进程一般都是孤儿进程
创建守护进程 1.忽略可能引起异常退出的信号 例如SIG_CHLD SIG_PIPE 2.让父进程退出 3.让自己成为一个新的会话setsid 4.将进程的CWD更改为/根目录 提高效率 chdir 5.独立的会话组也就是说没有bash进程了所以可以将所有文件dup(nullfd1/0/2) /dev/null
tips:1.命名守护进程我们都以d结尾 2.kill -9 ls /proc/pid -l
#include iostream
#include signal.h
#include unistd.h
#include sys/types.h
#include sys/stat.h
#include fcntl.husing namespace std;const char *rootdic /;
const char *nulldic /dev/null;
void Daemon(bool isroot, bool isclose)
{// 忽略可能引起异常的型号signal(SIGCHLD, SIG_IGN);signal(SIGPIPE, SIG_IGN);// 守护进程不能是组长所以得创建孤儿进程pid_t id fork();if (id ! 0)exit(0);// 创建一个新的会话setsid();// 根目录if (isroot){chdir(rootdic);}if (isclose){close(0);close(1);close(2);}else{int nullfd open(nulldic, O_WRONLY);if (nullfd 0){dup2(nullfd, 0);dup2(nullfd, 1);dup2(nullfd, 2);close(nullfd);}}
}
系统有没有将进程守护化的方法 daemon 将服务器守护化,但企业一般都自己会实现进程守护化