
- 字节序,即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前。
- 字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。

#include
uint16_t htons(uint16_t host16bitvalue); //返回网络字节序的值
uint32_t htonl(uint32_t host32bitvalue); //返回网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue); //返回主机字节序的值
uint32_t ntohl(uint32_t net32bitvalue); //返回主机字节序的值



int socket(int domain, int type, int protocol);


int inet_aton(const char* straddr,struct in_addr *addrp);char* inet_ntoa(struct in_addr inaddr); 监听


连接

数据收发
5.1 数据收发常用第一套API

5.2 数据收发常用第二套API

客户端的connect函数

man 2 socket、man 2 bind、man htons、man inet_atoncd /usr/includelsgrep "struct sockaddr_in {" * -nir
vi linux/in.h +261

grep "struct in_addr {" * -nirvi linux/in.h +89

#include //printf
#include //socket bind /* See NOTES */
#include //socket bind
//#include //struct sockaddr_in//和冲突
#include //htons
#include //inet_aton
#include //exit
//int socket(int domain, int type, int protocol);
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*struct sockaddr_in {//也可在中找到
__kernel_sa_family_t sin_family; /* Address family */
//__be16 sin_port; /* Port number */
//struct in_addr sin_addr; /* Internet address */
/* Pad to size of `struct sockaddr'. */
//unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
// sizeof(unsigned short int) - sizeof(struct in_addr)];
//};*/
/*struct in_addr {
__be32 s_addr;
};*/
//int listen(int sockfd, int backlog);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//fd,客户端地址,客户端地址长度地址,返回新的建立的socket的通道
int main(int argc, char **argv)
{
int s_fd;
//1. socket 获取/创建套接字
s_fd = socket(AF_INET, SOCK_STREAM, 0);//IPv4 因特网域,TCP协议,自动选择type类型对应的默认协议(也可用宏:IPPROTO_TCP TCP)
if(s_fd == -1){//判断建立socket通道是否成功
perror("socket");//把错误的问题打出来
exit(-1);//退出这个程序
}
//2. bind 绑定
struct sockaddr_in s_addr;
s_addr.sin_family = AF_INET;//协议族,跟domain一致
s_addr.sin_port = htons(8989);//端口号一般3000以下为操作系统来用,建议用户5000以上 端口号由主机to网络 返回网络字节序的值
inet_aton("192.168.2.13",&s_addr.sin_addr);//本机ip地址由字符串形式to网络格式//ifconfig
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//把ip地址端口号和s_fd绑定起来//fd,强转为struct sockaddr型,结构体的长度
//3. listen
listen(s_fd,10);//监听10个连接,不阻塞
//4. accept 接受
int c_fd = accept(s_fd,NULL,NULL);//先不关心客户端是谁//如果没连接到,会卡在这//后续的操作用新的c_fd
//5. read
//6. write
printf("connected!\n");
while(1)//有客户端连上,不让其退出
return 0;
}


ifconfig 本机网络地址和本机回环地址:





#include //printf
#include //socket bind /* See NOTES */
#include //socket bind
//#include //struct sockaddr_in//和冲突
#include //htons
#include //inet_aton
#include //exit
#include //memset
#include //read write
//int socket(int domain, int type, int protocol);
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*struct in_addr {
__be32 s_addr;
};*/
//int listen(int sockfd, int backlog);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//fd,客户端地址,客户端地址长度,返回新的建立的socket的通道
int main()
{
int s_fd;//1. socket
int c_fd;//4. accept
int n_read;//5. read
char readBuf[128];//5. read//定义一个数组就不用像指针还要开辟空间
char *msg = "I get your connection\n";//6. write
struct sockaddr_in s_addr;//2. bind
struct sockaddr_in c_addr;//2. bind
memset(&s_addr,0,sizeof(struct sockaddr_in));//清空
memset(&c_addr,0,sizeof(struct sockaddr_in));//清空
//1. socket 获取/创建套接字
s_fd = socket(AF_INET, SOCK_STREAM, 0);//IPv4 因特网域,TCP协议,自动选择type类型对应的默认协议(也可用宏:IPPROTO_TCP TCP)
if(s_fd == -1){//判断建立socket通道是否成功
perror("socket");//把错误的问题打出来
exit(-1);//退出这个程序
}
//2. bind 绑定
s_addr.sin_family = AF_INET;//协议族,跟domain一致
s_addr.sin_port = htons(8989);//端口号一般3000以下为操作系统来用,建议用户5000以上 端口号由主机to网络 返回网络字节序的值
inet_aton("192.168.2.13",&s_addr.sin_addr);//本机ip地址由字符串形式to网络格式//ifconfig
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//把ip地址端口号和s_fd绑定起来
//3. listen
listen(s_fd,10);//监听10个连接
//4. accept 接受
int clen = sizeof(struct sockaddr_in);
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);//如果没连接到,会卡在这
if(c_fd == -1){
perror("accept");
}
printf("get connected: %s\n",inet_ntoa(c_addr.sin_addr));//连上后打印 “已连接” 和客户端的 ip地址
//5. read
n_read = read(c_fd, readBuf, 128);
if(n_read == -1){
perror("read");
}else{
printf("get message:%d,%s\n",n_read,readBuf);//打印收到了多少个字节的消息,和消息的内容
}
//6. write
write(c_fd,msg,strlen(msg));//用提前定义的字符串,如直接写入字符串,字节大小也随意写如128,会造成乱码因有无用的字节
return 0;
}

man 2 connect#include
#include /* See NOTES */
#include
//#include
#include
#include
#include
#include
#include //read write
//int socket(int domain, int type, int protocol);
//int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int main(int argc, char **argv)
{
int c_fd;//1. socket
int n_read;//4. read
char readBuf[128];//4. read
char *msg = "I'm a msg from Client";//3. write
//1. socket 获取/创建套接字
c_fd = socket(AF_INET, SOCK_STREAM, 0);
if(c_fd == -1){
perror("socket");
exit(-1);
}
//2.connect//连接服务器
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(8989);
inet_aton("192.168.2.13",&c_addr.sin_addr);//服务器的ip地址
if(connect(c_fd, (struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){//连接时会阻塞,直到出结果为之
perror("connect");
exit(-1);
}
//3. write//写
write(c_fd,msg,strlen(msg));
//4. read//读
n_read = read(c_fd, readBuf, 128);
if(n_read == -1){
perror("read");
}else{
printf("get message from server:%d,%s\n",n_read,readBuf);//打印收到了多少个字节的消息,和消息的内容
}
return 0;
}


#include //printf
#include //socket bind /* See NOTES */
#include //socket bind
//#include //struct sockaddr_in//冲突
#include //htons
#include //inet_aton
#include //exit
#include //memset
#include //read write
//int socket(int domain, int type, int protocol);
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*struct in_addr {
__be32 s_addr;
};*/
//int listen(int sockfd, int backlog);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//fd,客户端地址,客户端地址长度,返回新的建立的socket的通道
int main(int argc, char **argv)
{
int s_fd;//1. socket
int c_fd;//4. accept
int n_read;//5. read
char readBuf[128];//5. read
// char *msg = "I get your connection";
char msg[128] = {0};//6. write
struct sockaddr_in s_addr;//2. bind
struct sockaddr_in c_addr;//2. bind
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
if(argc != 3){//如果没有输入参数 会提示
printf("param is not good\n");
exit(-1);
}
//1. socket 获取套接字
s_fd = socket(AF_INET, SOCK_STREAM, 0);//IPv4 因特网域,TCP协议,自动选择type类型对应的默认协议(也可用宏:IPPROTO_TCP TCP)
if(s_fd == -1){//判断建立socket通道是否成功
perror("socket");//把错误的问题打出来
exit(-1);//退出这个程序
}
//2. bind 绑定
s_addr.sin_family = AF_INET;//协议族,跟domain一致
s_addr.sin_port = htons(atoi(argv[2]));//字符串转换为整形数
inet_aton(argv[1],&s_addr.sin_addr);//本机ip地址由字符串形式to网络格式//ifconfig
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//把ip地址端口号和s_fd绑定起来
//3. listen
listen(s_fd,10);//监听10个连接
//4. accept 接受连接
int clen = sizeof(struct sockaddr_in);
while(1){//不让程序退出 一直循环进行//不要在while(1)里定义变量
//同时收和发
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);//如果没连接到,会卡在这
if(c_fd == -1){
perror("accept");
}
printf("get connected: %s\n",inet_ntoa(c_addr.sin_addr));//连上后打印 “已连接” 和客户端的 ip地址
if(fork() == 0){//在网络服务进程中父进程等待客户端的服务请求 当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达
//6. write
if(fork()==0){//如果要用两个while(1),要么用多线程,要么用fork创建子进程
while(1){
memset(msg,0,sizeof(msg));
printf("input: ");
//gets(msg);//gets不安全,已经被废弃
fgets(msg,sizeof(msg),stdin);//阻塞
msg[strcspn(msg, "\n")] = '\0';//移除输入中的换行符
write(c_fd,msg,strlen(msg));//6. write
}
}
//5. read
while(1){
memset(readBuf,0,sizeof(readBuf));//每次写之前清空
n_read = read(c_fd, readBuf, 128);//阻塞
if(n_read == -1){
perror("read");
}else{
printf("get message from client:%d,%s\n",n_read,readBuf);//打印收到了多少个字节的消息,和消息的内容
}
}
}
}
return 0;
}
#include
#include /* See NOTES */
#include
//#include
#include
#include
#include
#include
#include //read write
//int socket(int domain, int type, int protocol);
//int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//char *fgets(char *s, int size, FILE *stream);
int main(int argc, char **argv)
{
int c_fd;//1. socket
int n_read;//4. read
char readBuf[128];//4. read
//char *msg = "I'm a msg from Client";//3. write
char msg[128] = {0};
if(argc != 3){//如果没有输入参数 会提示
printf("param is not good\n");
exit(-1);
}
//1. socket 获取/创建套接字
c_fd = socket(AF_INET, SOCK_STREAM, 0);
if(c_fd == -1){
perror("socket");
exit(-1);
}
//2.connect 连接服务器
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&c_addr.sin_addr);//服务器的ip地址
if(connect(c_fd, (struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){//连接时阻塞 成功后往下
perror("connect");
exit(-1);
}
while(1){//不让程序退出 一直循环进行
//同时发和收
//3. write 写
if(fork()==0){//如果要用两个while(1),要么用多线程,要么用fork创建子进程
while(1){
memset(msg,0,sizeof(msg));//每次写之前清空
printf("input: ");
//gets(msg);//gets不安全,已经被废弃
fgets(msg,sizeof(msg),stdin);//阻塞
msg[strcspn(msg, "\n")] = '\0';//移除输入中的换行符
write(c_fd,msg,strlen(msg));
}
}
//4. read 读
while(1){
memset(readBuf,0,sizeof(readBuf));
n_read = read(c_fd, readBuf, 128);//阻塞
if(n_read == -1){
perror("read");
}else{
printf("get message from server:%d,%s\n",n_read,readBuf);//打印收到了多少个字节的消息,和消息的内容
}
}
}
return 0;
}


#include //printf
#include //socket bind /* See NOTES */
#include //socket bind
//#include //struct sockaddr_in//冲突
#include //htons
#include //inet_aton
#include //exit
#include //memset
#include //read write
//int socket(int domain, int type, int protocol);
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*struct in_addr {
__be32 s_addr;
};*/
//int listen(int sockfd, int backlog);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//fd,客户端地址,客户端地址长度,返回新的建立的socket的通道
int main(int argc, char **argv)
{
int s_fd;//1. socket
int c_fd;//4. accept
int n_read;//5. read
int mark = 0;//第几个客户端
char readBuf[128];//5. read
// char *msg = "I get your connection";
char msg[128] = {0};//6. write
struct sockaddr_in s_addr;//2. bind
struct sockaddr_in c_addr;//2. bind
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
if(argc != 3){//如果没有输入参数 会提示
printf("param is not good\n");
exit(-1);
}
//1. socket 获取套接字
s_fd = socket(AF_INET, SOCK_STREAM, 0);//IPv4 因特网域,TCP协议,自动选择type类型对应的默认协议(也可用宏:IPPROTO_TCP TCP)
if(s_fd == -1){//判断建立socket通道是否成功
perror("socket");//把错误的问题打出来
exit(-1);//退出这个程序
}
//2. bind 绑定
s_addr.sin_family = AF_INET;//协议族,跟domain一致
s_addr.sin_port = htons(atoi(argv[2]));//字符串转换为整形数
inet_aton(argv[1],&s_addr.sin_addr);//本机ip地址由字符串形式to网络格式//ifconfig
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//把ip地址端口号和s_fd绑定起来
//3. listen
listen(s_fd,10);//监听10个连接
//4. accept 接受连接
int clen = sizeof(struct sockaddr_in);
while(1){//不让程序退出 一直循环进行//不要在while(1)里定义变量
//同时收和发
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);//如果没连接到,会卡在这
if(c_fd == -1){
perror("accept");
}
mark++;
printf("get connected: %s\n",inet_ntoa(c_addr.sin_addr));//连上后打印 “已连接” 和客户端的 ip地址
if(fork() == 0){//在网络服务进程中父进程等待客户端的服务请求 当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达//一有客户端接入就调用子进程
//6. write
if(fork()==0){//如果要用两个while(1),要么用多线程,要么用fork创建子进程
while(1){
sprintf(msg,"welcome NO.%d Client",mark);//每个客户端都能知道其连接有无丢失
write(c_fd,msg,strlen(msg));//6. write//对于服务端都能收到客户端的请求
sleep(3);//类似心跳包,每隔3s发一串话
}
}
//5. read
while(1){//接收每一个客户端发来的消息
memset(readBuf,0,sizeof(readBuf));//每次写之前清空
n_read = read(c_fd, readBuf, 128);//阻塞
if(n_read == -1){
perror("read");
}else{
printf("get message from NO.%d Client :%d,%s\n",mark,n_read,readBuf);//打印收到了多少个字节的消息,和消息的内容
}
}
}
}
return 0;
}















#include //socket bind.. /* See NOTES */
#include //socket bind listen accept
#include //open
#include //open
#include //htons
#include //fflush printf popen
#include //exit
#include //memset
#include //read write
#define LS 8
#define CD 5
#define PWD 9
#define PUT 6
#define GET 10
#define QUIT 4
#define GETFILE 11
//int access(const char * pathname,int mode);
//int chdir(const char *path);
struct Msg
{
int type;
char cmd[50];
char data[5120];
};
int get_cmd_type(char *cmd)//命令识别
{
cmd = strtok(cmd,"\n");//客户端获取用户输入时会使用enter键,so传输到服务器的命令都带有换行符,把\n分割走
if(!strcmp("ls",cmd)) return LS;//俩字符串相等返回0
if(strstr(cmd,"cd") != NULL) return CD;//如果前包含后,返回后在前首次出现的地址
if(strstr(cmd,"get") != NULL) return GET;
if(strstr(cmd,"put") != NULL) return PUT;
if(!strcmp("pwd",cmd)) return PWD;
if(!strcmp("quit",cmd)) return QUIT;
return 100;//在未识别的命令类型时可以执行特定的操作
}
char *str_decompose(char *cmd)//命令分割//将带有文件名、路径名的命令进行处理分割
{ //如命令“get 1.c”,该函数就会返回1.c
strtok(cmd," ");//第一个单词
cmd = strtok(NULL," ");//第二个单词往后
return cmd;
}
void cmd_handle(int ret,struct Msg msg,int c_fd)//命令处理
{
FILE *fp = NULL;
int n_fread;
char *dir = NULL;
char *file = NULL;
//char *file_path = "./";//当前路径
int file_fd;
int file_size;
switch(ret){
case LS:
case PWD:
msg.type = 0;
fp = popen(msg.cmd,"r");//调用终端执行ls/pwd命令,并将数据存放到fp文件流中
if(fp == NULL){
perror("popen");
}
memset(msg.data,0,sizeof(msg.data));
n_fread = fread(msg.data,1,sizeof(msg.data),fp);//读取文件流的数据到msg.data
write(c_fd,&msg,sizeof(msg));//向客户端发送/返回数据
fflush(stdout);//强制刷新标准输出缓冲区,把输出缓冲区里的东西强制打印到标准输出设备(终端)
break;
case CD:
dir = str_decompose(msg.cmd);
printf("dir:%s\n",dir);//打印需要cd的目录名
if(chdir(dir) <0){//修改当前的工作目录
perror("chdir");
}
break;
case GET://下载文件内容到本地的文件
file = str_decompose(msg.cmd);
if(access(file,F_OK) < 0){ //判断服务器是否存在客户端想要下载的文件
msg.type = 0;
memset(msg.data,0,sizeof(msg.data));
strcpy(msg.data,"Target file doesn't exist!");
write(c_fd,&msg,sizeof(msg));
}else if(access(file,R_OK) < 0){ //判断服务器是否对该文件有读权限
msg.type = 0;
memset(msg.data,0,sizeof(msg.data));
strcpy(msg.data,"The target file doesn't have read-permission!");
write(c_fd,&msg,sizeof(msg));
}else{ //获取该文件的内容,发送给客户端
msg.type = GETFILE;//下载文件
file_fd = open(file,O_RDWR);//打开文件
if(file_fd < 0){
perror("open");
}
file_size = lseek(file_fd,0,SEEK_END);
if(file_size < 0){
perror("lseek");
}
lseek(file_fd,0,SEEK_SET);//光标偏移至头
memset(msg.data,0,sizeof(msg.data));
if(read(file_fd,msg.data,file_size) < 0){//把文件内容读到msg.data
perror("read");
}
close(file_fd);
write(c_fd,&msg,sizeof(msg));
}
break;
case PUT://创建一个文件,写入客户端想要存放的文件的数据(上传)
file = str_decompose(msg.cmd);
file_fd = open(file,O_RDWR|O_CREAT,0666);
if(file_fd < 0){
perror("open");
}
if(write(file_fd,msg.data,strlen(msg.data)) < 0){
perror("write");
}
close(file_fd);
break;
case QUIT:
printf("client quit!\n");
exit(0);
break;
}
}
int main(int argc,char **argv)
{
if(argc != 3){//参数不足或不一致的提示
printf("Insufficient or inconsistent parameters\n");
exit(-1);
}
//1. socket
int s_fd = socket(AF_INET,SOCK_STREAM,0); //创建套接字:IPV4因特网域,流式套接字、TCP传输协议
if(s_fd == -1){
printf("socket failed\n");
perror("socket");
exit(-1);
}
//2. bind
struct sockaddr_in s_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in));
s_addr.sin_family = AF_INET;//IPV4因特网域
s_addr.sin_port = htons(atoi(argv[2]));//将端口号转化成网络字节序
inet_aton(argv[1],&s_addr.sin_addr);//将IP地址转化为网络字节序
int bd = bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//为套接字添加网络信息
if(bd == -1){
printf("bind failed\n");
perror("bind");
exit(-1);
}
//3. listen
int ln= listen(s_fd,10);//监听10个客户端的连接
if(ln == -1){
printf("listen failed\n");
perror("listen");
exit(-1);
}
//4. accept
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
int c_fd;//连接文件描述符
int clt = sizeof(struct sockaddr_in);
int mark = 0;//客户端数量标志
pid_t pid;
while(1){
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clt);//等待客户端的连接,返回c_fd
if(c_fd == -1){
printf("accept failed\n");
perror("accept");
exit(-1);
}
mark++;//客户端标志+1
printf("get No.%d connection: %s\n",mark,inet_ntoa(c_addr.sin_addr));
pid = fork();//当有客户端连接时,创造一个子进程去读取客户端发送的命令
if(pid < 0){
perror("fork");
exit(-1);
}
else if(pid == 0){
struct Msg msg;
int c_read;
int ret;
while(1){
memset(msg.cmd,0,sizeof(msg.cmd));
c_read = read(c_fd,&msg,sizeof(msg));//读取客户端发送的命令
if(c_read <= 0){
perror("read");
break;
}else{
printf("get message %d's cmd from NO.%d Client :%s\n",c_read,mark,msg.cmd);
ret = get_cmd_type(msg.cmd);//对客户端传送的命令进行识别
cmd_handle(ret,msg,c_fd);//对相关命令进行处理
}
}
}
close(c_fd);
}
close(s_fd);
return 0;
}
#include //socket bind.. /* See NOTES */
#include //socket bind listen accept
#include
#include //open
#include //htons
#include //fflush printf popen
#include //exit
#include //memset
#include //read write
#define LLS 1
#define LCD 2
#define LPWD 3
#define QUIT 4//本地执行的命令
#define CD 5//本地发送指令,远程要执行的命令无返回数据
#define PUT 6//本地发送数据,远程要执行的命令无返回数据
#define CMD 7//ifgo是否返回数据
#define LS 8
#define PWD 9
#define GET 10//远程要执行的远程命令会返回数据到本地
#define GETFILE 11//msg.type
// int access(const char * pathname,int mode);
struct Msg
{
int type;
char cmd[50];
char data[5120];
};
int get_cmd_type(char *cmd)//命令识别
{
cmd = strtok(cmd,"\n");//客户端获取用户输入时会使用enter键,so传输到服务器的命令都带有换行符,把\n分割走
if(!strcmp("lls",cmd)) return LLS;
if(strstr(cmd,"lcd") != NULL) return LCD;
if(!strcmp("lpwd",cmd)) return LPWD;
if(!strcmp("quit",cmd)) return QUIT;//本地执行的命令
if(strstr(cmd,"cd") != NULL) return CD;
if(strstr(cmd,"put") != NULL) return PUT;
if(!strcmp("ls",cmd)) return LS;
if(!strcmp("pwd",cmd)) return PWD;
if(strstr(cmd,"get") != NULL) return GET;
return -1;//后续可处理未识别的命令
}
char *str_decompose(char *cmd)//命令分割//将带有文件名、路径名的命令进行处理分割
{ //如命令“get 1.c”,该函数就会返回1.c
strtok(cmd," ");//第一个单词
cmd = strtok(NULL," ");//第二个单词往后
return cmd;
}
int cmd_handle(int ret,struct Msg msg,int s_fd)//命令处理
{
FILE *fp = NULL;
//char *file_path = "./";
char *file = NULL;
int file_fd;
int file_size;
char buf[32];
switch(ret){
case LLS:
printf("--------------------------------------\n");
system("ls");//调用终端执行ls命令,并将数据输出到标准输出上
printf("--------------------------------------\n");
break;
case LCD:
if(chdir(str_decompose(msg.cmd)) < 0){//修改当前工作目录
perror("chdir");
}
break;
case LPWD:
printf("--------------------------------------\n");
system("pwd"); //调用终端执行pwd命令,并将数据输出到标准输出上
printf("--------------------------------------\n");
break;
case QUIT:
write(s_fd,&msg,sizeof(msg));
printf("--------------------------------------\n");
printf("client is quit\n");
printf("--------------------------------------\n");
exit(0);//退出当前进程
break;
case CD:
case LS:
case PWD:
case GET:
msg.type = 0;
write(s_fd,&msg,sizeof(msg));//将用户输入发送给服务器,让服务器根据命令进行相应的行为
break;
case PUT:
strcpy(buf,msg.cmd); //put 1.c -> msg.cmd
file = str_decompose(buf);//1.cc
if(access(file,F_OK) < 0){//判断客户端是否拥有想要存放到服务器的文件
printf("--------------------------------------\n");
printf("Target file doesn't exist!\n");
printf("--------------------------------------\n");
}else if(access(file,R_OK) < 0){//判断客户端是否对该文件有读权限
printf("--------------------------------------\n");
printf("The target file doesn't have read-permission!\n");
printf("--------------------------------------\n");
}else{//获取该文件的内容,发送给服务器
file_fd = open(file,O_RDWR);
if(file_fd < 0){
perror("open");
}
file_size = lseek(file_fd,0,SEEK_END);
if(file_size < 0){
perror("lseek");
}
lseek(file_fd,0,SEEK_SET);
memset(msg.data,0,sizeof(msg.data));
if(read(file_fd,msg.data,sizeof(msg.data)) < 0){
perror("read");
}
close(file_fd);
write(s_fd,&msg,sizeof(msg));
printf("--------------------------------------\n");
printf("Target file is on server!\n");
printf("--------------------------------------\n");
}
break;
default:
printf("--------------------------------------\n");
printf("Input error, please re-enter!\n");
printf("--------------------------------------\n");
break;
}
return ret;
}
void from_socket_data_handle(struct Msg msg,int s_fd)//对服务器发送的数据进行处理
{
struct Msg socket_msg;
int n_read;
int file_fd;
char file_path[20] = "./";
n_read = read(s_fd,&socket_msg,sizeof(socket_msg));
if(n_read == -1){
perror("read socket");
exit(-1);
}else if(socket_msg.type == GETFILE){//如果是GETFILE指令返回的数据,就存进文件中
strcat(file_path,str_decompose(msg.cmd));//./demo.c//也可不用拼接./
file_fd = open(file_path,O_RDWR|O_CREAT,0666);//创建文件a
write(file_fd,socket_msg.data,strlen(socket_msg.data));//向a中写入下载的文件内容
fflush(stdout);//强制刷新
close(file_fd);
printf("--------------------------------------\n");
printf("%s","Get target file from server!\n");
printf("--------------------------------------\n");
}else{//如果是其他数据就直接打印出来
printf("--------------------------------------\n");
printf("%s",socket_msg.data);
printf("--------------------------------------\n");
}
}
int main(int argc,char **argv)
{
if(argc != 3){//参数不足或不一致的提示
printf("Insufficient or inconsistent parameters\n");
exit(-1);
}
//1. socket
int s_fd = socket(AF_INET,SOCK_STREAM,0); //创建套接字:IPV4因特网域,流式套接字、TCP传输协议
if(s_fd == -1){
printf("socket failed\n");
perror("socket");
exit(-1);
}
//2. connect
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
c_addr.sin_family = AF_INET;//IPV4因特网域
c_addr.sin_port = htons(atoi(argv[2]));//将端口号转化成网络字节序
inet_aton(argv[1],&c_addr.sin_addr);//将IP地址转化为网络字节序
if(connect(s_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1){//客户端连接服务器
perror("connect");
exit(-1);
}
//3. write & read
struct Msg msg;
int ret;
int tmp;
while(1){
memset(msg.cmd,0,sizeof(msg.cmd));
memset(msg.data,0,sizeof(msg.data));
printf(">");
fgets(msg.cmd,sizeof(msg.cmd),stdin); //获取用户输入的命令
ret = get_cmd_type(msg.cmd); //对用户键入的命令进行识别
tmp = cmd_handle(ret,msg,s_fd); //对命令进行处理
if(tmp > CMD){
from_socket_data_handle(msg,s_fd);//对服务器传送的数据进行处理
}
fflush(stdout);//强制刷新
}
close(s_fd);
return 0;
}