socket实现不同服务器上的进程间的通信。
socket是一个伪文件,分成两个部分:读缓冲区和写缓冲区。所以socket一旦建立就会在PCB中对应生成一个文件描述符fd。
socket必须成对出现。
=============================
网络字节序:
大小端:小端,低位存低地址,高位存高地址。大端相反。
总之在网络间传递的包都是大端。
网络字节序和主机字节序的转换
点分十进制转网络大端
#include <stdio.h>
#include <arpa/inet.h>
int main(int argc,char *argv[])
{
//准备转换成大端的IP地址
char buf[]="192.168.136.101";
unsigned int num=0;
//转成大端
inet_pton(AF_INET,buf,&num);
unsigned char * p=(unsigned char *)#
printf("%d %d %d %d\n",*p,*(p+1),*(p+2),*(p+3));
//大端转小端
char ip[16]="";
printf("%s\n",inet_ntop(AF_INET,&num,ip,16));
return 0;
}
IPV4套接字结构体
我们需要指定的就是协议 IP 端口,将这三个东西封装成一个结构体
man 7 ip
IPV4套接字结构体
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET 协议 */
in_port_t sin_port; /* port in network byte order 端口*/
struct in_addr sin_addr; /* internet address IP地址*/
};/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
通用套接字结构体
TCP特点:出错重传,每次发送数据对方都会回ACK,可靠。
socket服务器编写
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
//创建套接字/文件描述符
int lfd = socket(AF_INET,SOCK_STREAM,0);
//绑定。将协议和端口转成大端封装进结构体
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
// addr.sin_addr.s_addr = INADDR_ANY;//绑定的是通配地址
//此处将文件描述符绑定到本服务器的IP地址
inet_pton(AF_INET,"192.168.136.101",&addr.sin_addr.s_addr);
int ret = bind(lfd,(struct sockaddr *)&addr,sizeof(addr));
if(ret < 0)
{
perror("");
exit(0);
}
//监听
listen(lfd,128);
//提取
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
int cfd = accept(lfd,(struct sockaddr *)&cliaddr,&len);
char ip[16]="";
printf("new client ip=%s port=%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,
ip,16), ntohs(cliaddr.sin_port));
//读写
char buf[1024]="";
while(1)
{
bzero(buf,sizeof(buf));
// int n = read(STDIN_FILENO,buf,sizeof(buf));
// write(cfd,buf,n);
int n =0;
n = read(cfd,buf,sizeof(buf));
if(n ==0 )//如果read返回等于0,代表对方关闭
{
printf("client close\n");
break;
}
printf("%s\n",buf);
}
//关闭
close(lfd);
close(cfd);
return 0;
}
三次握手
多进程实现并发服务器
与线程版进行对比
gcc 02_process_tcp_server.c wrap.c
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include "wrap.h"
void free_process(int sig)
{
pid_t pid;
while(1)
{
pid = waitpid(-1,NULL,WNOHANG);
if(pid <=0 )//小于0 子进程全部退出了 =0没有进程没有退出
{
break;
}
else
{
printf("child pid =%d\n",pid);
}
}
}
int main(int argc, char *argv[])
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGCHLD);
sigprocmask(SIG_BLOCK,&set,NULL);
//创建套接字,绑定
int lfd = tcp4bind(8008,NULL);
//监
Listen(lfd,128);
//提取
//回射
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
while(1)
{
char ip[16]="";
//提取连接,
int cfd = Accept(lfd,(struct sockaddr *)&cliaddr,&len);
printf("new client ip=%s port=%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,ip,16),
ntohs(cliaddr.sin_port));
//fork创建子进程
pid_t pid;
pid = fork();
if(pid < 0)
{
perror("");
exit(0);
}
else if(pid == 0)//子进程
{
//关闭lfd
close(lfd);
while(1)
{
char buf[1024]="";
int n = read(cfd,buf,sizeof(buf));
if(n < 0)
{
perror("");
close(cfd);
exit(0);
}
else if(n == 0)//对方关闭j
{
printf("client close\n");
close(cfd);
exit(0);
}
else
{
printf("%s\n",buf);
write(cfd,buf,n);
// exit(0);
}
}
}
else//父进程
{
close(cfd);
//回收
//注册信号回调
struct sigaction act;
act.sa_flags =0;
act.sa_handler = free_process;
sigemptyset(&act.sa_mask);
sigaction(SIGCHLD,&act,NULL);
sigprocmask(SIG_UNBLOCK,&set,NULL);
}
}
//关闭
return 0;
}
1
2
3
线程版服务器
#include <stdio.h>
#include <pthread.h>
#include "wrap.h"
typedef struct c_info
{
int cfd;
struct sockaddr_in cliaddr;
}CINFO;
void* client_fun(void *arg);
int main(int argc, char *argv[]){
if(argc<2)
{
printf("argc<2 >>>> \n ./a.out 8000 \n");
return 0;
}
short port=atoi(argv[1]);
int lfd=tcp4bind(port,NULL);
Listen(lfd,128);
struct sockaddr_in cliaddr;
socklen_t len=sizeof(cliaddr);
CINFO *info;
while(1){
int cfd=Accept(lfd,(struct sockaddr *)&cliaddr,&len);
char ip[16]="";
printf("new client ip =%s port=%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,ip,16),
ntohs(cliaddr.sin_port)
);
pthread_t pthid;
info=malloc(sizeof(CINFO));
info->cfd=cfd;
info->cliaddr=cliaddr;
pthread_create(&pthid,NULL,client_fun,info);
}
return 0;
}
void* client_fun(void *arg)
{
CINFO *info=(CINFO *)arg;
char ip[16]="";
printf("new client ip =%s port=%d\n",inet_ntop(AF_INET,&(info->cliaddr.sin_addr.s_addr),ip,16),
ntohs(info->cliaddr.sin_port));
while(1)
{
char buf[1024]="";
int count=0;
count =read(info->cfd,buf,sizeof(buf));
if(count<0)
{
printf("client close\n");
break;
}
else if (count==0)
{
printf("clent close\n");
break;
}
else
{
printf("%s\n",buf);
write(info->cfd,buf,count);
}
}
close(info->cfd);
free(info);
}