网络编程day2-套接字与TPC服务器与客户端的搭建
1.思维导图
2. TPC服务器与客户端的搭建
要点:动态协议包防止粘包
服务器
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
enum Type
{
TYPE_REGIST,//注册
TYPE_LOGIN //登录
};
typedef struct Pack
{
int size;
enum Type type;
char buf[2048];
int count;
}pack_t;
void read_pack(pack_t* pack)
{
char* buf=pack->buf;
int readed_size = 0;
while(1)
{
short data_size = *(short*)(buf+readed_size);
if(data_size==0)
{
// printf("数据解析完毕\n");
break;
}
readed_size+=2;
char temp[data_size+1];
memset(temp,0,data_size+1);
memcpy(temp,buf+readed_size,data_size);
readed_size+=data_size;
printf("temp=%s\n",temp);
}
}
int main(int argc, const char *argv[])
{
if(argc!=2)
{
printf("请输入端口号\n");
return 1;
}
// ./server 7777
int port=atoi(argv[1]);//将字符串 7777 转换为int 类型port
//创建服务器套接字
int server = socket(AF_INET,SOCK_STREAM,0);
//准备网络地址结构体:struct sockaddr_in
addr_in_t addr={0};
addr.sin_family = AF_INET;//固定
addr.sin_port=htons(port);//port转换为网络字节序
addr.sin_addr.s_addr = inet_addr("0.0.0.0");//ip转换为unsigned int
//为服务器套接字绑定ip和port
if(bind(server,(addr_t*)&addr,sizeof(addr))==-1)//需要强转
{
perror("bind");
return 1;
}
//监听
listen(server,10);
//接受客户端的连接
addr_in_t cilent_addr={0};
int cilent_addr_len =sizeof(cilent_addr);
int cilent = accept(server,(addr_t*)&cilent_addr,&cilent_addr_len);//需要强转
if(cilent!=-1)
{
printf("有客户端连接\n");
}
//读取客户端发来的消息
while(1)
{
int pack_size=0;
read(cilent,&pack_size,4);//先读取size
pack_t pack={0};
int res=read(cilent,(char*)&pack+4,pack_size-4);//读取size后的内容
if(res==0)
{
printf("客户端断开连接\n");
break;
}
pack.size=pack_size;//给新创建的size赋值
read_pack(&pack);
}
return 0;
}
客户端
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
enum Type
{
TYPE_REGIST,//注册
TYPE_LOGIN //登录
};
typedef struct Pack//协议包
{
int size; //用来记录整个协议包的实际大小,占四个字节 定长部分
enum Type type;//占4个字节 变长部分
char buf[2048];//占count个字节 不传输部分
int count;//用来记录指针的偏移量,也就是buf使用了多少字节
}pack_t;
void append(pack_t* pack,const char* data)
{
char* buf=pack->buf;
int len=strlen(data);
*(short*)(buf+pack->count)=len;//将buf的前两个字节当做short来存储数据len
pack->count+=2;//偏移两个字节
memcpy(buf+pack->count,data,len);//把数据内容拷贝到buf中
pack->count+=len;//偏移数据长度个字节
pack->size=pack->count+8;
}
int main(int argc, const char *argv[])
{
if(argc!=2)
{
printf("请输入端口号:\n");
return 1;
}
int port=atoi(argv[1]);//获取端口号
int cilent=socket(AF_INET,SOCK_STREAM,0);//创建客户端套接字
addr_in_t addr={0};
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
addr.sin_addr.s_addr=inet_addr("192.168.217.128");
if(connect(cilent,(addr_t*)&addr,sizeof(addr))==-1)//连接服务器
{
perror("connect");
return 1;
}
while(1)
{
pack_t pack={0};
char name[20]="";
char pswd[20]="";
pack.type=TYPE_REGIST;
printf("请输入账号:");
scanf("%20s",name);
while(getchar()!=10);
printf("请输入密码:");
scanf("%20s",pswd);
while(getchar()!=10);
append(&pack,name);
append(&pack,pswd);
write(cilent,&pack,pack.size);//type占了四个字节
}
return 0;
}