1.包裹函数
对服务器客户端等函数进行报错处理 以及简化处理
比如bind
int tcp4bind(short port,const char *IP)
{
struct sockaddr_in serv_addr;
int lfd = Socket(AF_INET,SOCK_STREAM,0);
bzero(&serv_addr,sizeof(serv_addr));
if(IP == NULL){
//如果这样使用 0.0.0.0,任意ip将可以连接
serv_addr.sin_addr.s_addr = INADDR_ANY;
}else{
if(inet_pton(AF_INET,IP,&serv_addr.sin_addr.s_addr) <= 0){
perror(IP);//转换失败
exit(1);
}
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
// int opt = 1;
//setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
Bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
return lfd;
}
2.粘包
缓冲区内 由于没发送完毕另外一个包就来了直接挤占前一个包的缓冲区(被信号打断的情况
解决方式
1.约定 一次发送固定字节数
2.数据结尾要\n
3.头部加上数据的大小
3.三次握手规则
SYN 包体中的1
4.四次挥手
FIN
四次握手序号
5.滑动窗口
mms
mss 出现三次握手前两次 告知对方发送数据最大长度
MTU 跟网卡有关系 一帧最大传输单元
6.TCP流量控制
TCP报文窗口尺寸 发送报文者的最大缓冲区
三次握手第2次告诉
发送流程
7.多进程(多线程)实现并发服务器
创建套接字
绑定
监听
while(1)
{
提取连接
fork创建子进程
子进程中,关闭lfd,服务客户端
父进程关闭cfd,回收子进程的资源
}
关闭
并发是指两个或多个事件在同一时间间隔内发生。
代码
#include<unistd.h>
#include<stdio.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<signal.h>
#include"wrap.h"
void free_process(int sig)
{
pid_t pid;
while (1)
{
pid = waitpid(-1, NULL, WNOHANG);
if (pid <= 0)
{
break;
}
else
{
printf("进程号%d 退出\n", pid);
}
}
}
int main()
{
//TCP bind ipv44
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_BLOCK, &set, NULL);
int lfd = tcp4bind(8000, NULL);
Listen(lfd, 128);
struct sockaddr_in as;
socklen_t len = sizeof(as);
while (1)
{
char ip[16] = "";
int cfd = Accept(lfd, (struct sockaddr*)&as, &len);
printf("新的主机 ip=%s port=%d \n", inet_ntop(AF_INET, &as.sin_addr.s_addr, ip, 16), ntohs(as.sin_port));
pid_t pid;
pid = fork();
if (pid < 0)
{
perror("fork");
exit(0);
}
else if (pid == 0)
{
while (1)
{
//字进程内部
close(lfd);
char buf[1024] = "";
int n = read(cfd, buf, sizeof(buf));
if (n < 0)
{
perror("");
close(cfd);
exit(0);
}
else if (0 == n)
{
printf("主机 ip=%s port=%d 即将断开链接 \n", inet_ntop(AF_INET, &as.sin_addr.s_addr, ip, 16), ntohs(as.sin_port));
close(cfd);
exit(0);
}
else
{
printf("%s\n", buf);
write(cfd, buf, n);
}
}
}
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;
}
多线程实现并发服务器
#include<unistd.h>
#include<stdio.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<signal.h>
#include"wrap.h"
#include <pthread.h>
typedef struct agv1
{
struct sockaddr_in cliaddr;
int cdf;
}agv1;
void* fun(void *arg)
{
agv1* info = (agv1*)arg;
//打印信息
char ip[16] = "";
printf("客户端 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->cdf, buf, sizeof(buf));
if (count == 0)
{
printf("客户端 ip=%s port=%d 链接即将断开 线程即将销毁 \n", inet_ntop(AF_INET, &(info->cliaddr.sin_addr.s_addr), ip, 16),
ntohs(info->cliaddr.sin_port));
break;
break;
}
else
{
printf("客户端%d : %s\n",ntohs(info->cliaddr.sin_port) ,buf);
}
}
close(info->cdf);
free(info);
//线程设置分离 自动回收
}
int main()
{
printf("请输入服务器端口号\n");
char buf[8] = "";
read(STDIN_FILENO, buf, sizeof(buf));
printf(" \n");
printf("等待客户端链接\n");
int port = atoi((char*)buf);
int G=9;
if(G==9)
{
//创建 绑定
int lfd=tcp4bind(port, NULL);
//监听
Listen(lfd, 128);
//提取
struct sockaddr_in as;
socklen_t len = sizeof(as);
agv1* info;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
while (1)
{
pthread_t pthid;
int cfd = Accept(lfd, (struct sockaddr*) & as, &len);
//创建线程 ->传递参数
info = malloc(sizeof(agv1));
info->cdf = cfd;
info->cliaddr = as;
//创建线程
pthread_create(&pthid, &attr, fun, info);
}
}
}
标签:info,多线程,addr,int,Linux,三次,include,buf,port
From: https://www.cnblogs.com/lzfyz/p/17572569.html