前言知识
sock udp编程
socket
用来创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol)
第一个参数代表了作用域,常用的一般就这三个
第二个参数是类型,用什么样的方式发送,选择udp或者tcp
第三个参数在这我们可以先忽略填0就ok
bind
bind的作用就是本地主机与套接字绑定
sockaddr_in结构体
里面包含了端口号port,本地地址addr还有common
local.sin_family=AF_INET
在该结构体中,family就代表协议家族的,这里默认和socket中第一个参数‘域’保持一致
local.sin_port=htons(_port)
port可以直接使用htons函数去转换
这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。 例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回 ; 如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回。
local.sin_addr.s_addr=inet_addr(_ip.c_str())
inet_addr函数可以直接将点分十进制ip转换成四个字节的数据存入local中
bind(_sock,(struct sockaddr*)&local,sizeof local)
recvfrom
从网络中接受数据消息,第一个参数是sockfd,sockfd相当于文件描述符,buff是缓冲区,flags是是否阻塞,这里默认填0,代表阻塞,src_addr是要将从网络中来的数据的套接字取到,addrelen是输入输出型参数,输入peer缓冲区大小,输出实际读取到的peer,成功读取到返回字节数量,不成功返回
sendto
回写给客户端数据
第一个参数还是文件描述符,第二个是缓冲区,第三个阻塞等待0,第四个客服端的套接字地址,第五个为输入输出型参数socklen_t
运行服务器成功
socket tcp编程
tcp是面向有连接的编程,需要连接上才能使用
多进程版tcp服务器
初始化服务器和udp一样,先创建套接字,和udp不同的是这里用的是SOCK_STREAM,代表了流式,而udp采用的是数据报的形式,然后因为是服务端,所以正常来说是绑定主机号的,绑定后后,使用listen去监听
void initserver(){
_listensock=socket(AF_INET,SOCK_STREAM,0);
if(_listensock<0){
logMessage(FATAL,"create sock error%d:%s",errno,strerror(errno));
exit(2);
}
logMessage(NORMAL,"create sock success:%d",_listensock);
struct sockaddr_in local;
memset(&local,0,sizeof local);
local.sin_family=AF_INET;
local.sin_port=htons(_port);
local.sin_addr.s_addr=_ip.empty()?INADDR_ANY:inet_addr(_ip.c_str());
if(bind(_listensock,(struct sockaddr*)&local,sizeof local)<0){
logMessage(FATAL,"bind error%d:%s",errno,strerror(errno));
exit(3);
}
logMessage(NORMAL,"bind local success:%d",_listensock);
if(listen(_listensock ,gbacklog)<0){
logMessage(FATAL,"listen error%d:%s",errno,strerror(errno));
exit(4);
}
logMessage(NORMAL,"init success") ;
}
这里在最开头做一个信号处理当子进程退出的时候直接忽略,那么就不会产生僵尸进程了,先创建数据结构sockaddr_in主要是存储ip和prot用的,这里是接收客户端的sock,拿到后创建子进程,处理接受数据。
void start(){
signal(SIGCHLD,SIG_IGN);
while(true){
struct sockaddr_in src;
socklen_t len=sizeof(src);
int sevicesock=accept(_listensock,(struct sockaddr*)&src,&len);
if(sevicesock<0){
logMessage(FATAL,"sevicesock create error%d:%s",errno,strerror(errno));
continue;
}
uint16_t clientport=ntohs(src.sin_port);
std::string clientip=inet_ntoa(src.sin_addr);
logMessage(NORMAL,"create sevicesock success%d %s %d",sevicesock,clientip.c_str(),clientport) ;
pid_t id=fork();
if(id==0){
close(_listensock);
sevice(sevicesock,clientip,clientport);
exit(0);
}
close(sevicesock);
}
}