Linux网络编程——基于tcp/ip的模拟聊天(文件传输)工具
开发平台:Linux
开发工具:Ubuntu, sourceInsight4.0
项目介绍: 本项目基于TCP/IP协议创建一个网络通信系统,可以实现客户之间的聊天通信以及文件传输,同时利用进程实现多客户群聊,多个客户也可同时从服务器下载文件实现文件共享,客户可向服务器发送ls命令获取服务器端的文件目录,并发送get+filename获取文件,也可发送put+filename上传文件到服务器。
protocol.h
#ifndef __PROTOCOL_H__
#define __PROTOCOL_H__#define FTP_ROOT_DIR "/home/gec/tftp"//命令号, 命令参数//命令号-> 整数
enum CMD_NO
{FTP_CMD_LS = 1024, //FTP_CMD_GET,FTP_CMD_PUT,FTP_CMD_BYE,FTP_CMD_NUM // 命令个数
};//出错码
enum resp_result
{RESP_SUCCESS = 0, //成功RESP_PACK_ERROR, //失败,包的长度不对RESP_PACK_NOEND, //包没有结束,可以再次收包RESP_PACK_NOFILE //没有可以获取的文件
};//参数: 参数长度, 参数内容/*0xc0 : 包头pkg_len ;//4bytes, 小端模式,整个数据包的长度4(pkg_len) + 4 (cmd_no) + arg_1 +...cmd_no // 4bytes, 小端模式arg_1;arg_1_len; //4bytes , 小端模式arg_1_data; len长度arg_2:arg_2_len; //4bytes,小端模式arg_2_data;....0xC0:包尾
*/// cmd: ls//0xc0 ___包长度______ __命令号()__ 0xc0
// 0xc0 0x80 0x00 0x00 0x00 //cmd: get
//0xc0 ____包长度(4)___ ___命令号(4)___ ___arg_1_Len(4)_ ___filename(r)___ 0xc0#if 0
unsigned char cmd[1024];
int i = 0;int pkg_len = 1024;cmd[0] = 0xc0;cmd[1] = pkg_len & 0xff;
cmd[2] = ( pkg_len >> 8) & 0xff;
cmd[3] = (pkg_len >> 16) & 0xff;
cmd[4] = (pkg_len >> 24) & 0xff;
#endif//CMD_RESP
/*0xc0: 包头pkg_len: 整个数据包的长度,4bytes, 小端模式cmd_no : 命令号,4bytes, 小端模式,表示回复哪条命令resp_len: 回复内容的长度,4bytes, 小端模式result + resp_conent1 + xresult: 执行成功或失败,1 bytes , 0表示成功,其他表示失败resp_conent: 回复内容成功:ls: 文件名字 各文件名之间用空格分隔get: 文件大小,4bytes, 小端模式失败:出错码0xc0:包尾
*///ls 的回复
// 0xc0 --pkg_Len(4)--- ---cmd_No(4)--- --resp_len(4)-- --result(1)-- --filenames(r, 名字以空格分开)--- 0xc0//get 的回复
//0xc0 ---pkg_len(4)--- ----cmd_no(4)--- ---resp_len(4)--- ---result(1)-- --file_size(4, 小端模式)-- 0xc0#endif
tcp_client.c
#include <sys/types.h> /* See NOTES */
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/socket.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include "protocol.h"int connect_server(char *ip,int port)
{
/**1.创建套接字**/int sockfd = socket(AF_INET,SOCK_STREAM,0);if(-1 == sockfd){perror("socket error");return -1;}/**2.发起链接请求**/int ret;struct sockaddr_in sAddr;memset(&sAddr,0,sizeof(sAddr));sAddr.sin_family = AF_INET;sAddr.sin_port = htons(port);sAddr.sin_addr.s_addr = inet_addr(ip);ret = connect(sockfd,(struct sockaddr*)&sAddr,sizeof(sAddr));if(-1 ==ret){perror("conncet error");return -1;}//return sockfd;
}void send_cmd(int sockfd,unsigned char *cmd,int len)
{//int ret = send(sockfd,cmd,len,0);if(-1 == ret){perror("send cmd error");return;}//
}void recv_ls_val(int sockfd)
{/**服务器回复数据,事先会回复一个数据包0xc0 L E N S E R R N S I Z E 0xc0 回复数据包长度 回复的验证信息 后续正文大小紧接着服务器会回复正文size个字节的数据**/int i=0;unsigned char ch = 0;unsigned char cmd[500] = {0};
/*************************************接收回复数据包*******************************************************/ //命令以0xc0开头,所以如果收到的不是0xc0则舍弃不要do{//read(sockfd,&ch,1);perror("read ls");}while(ch != 0xc0);////排除连续的0xc0while(ch == 0xc0){read(sockfd,&ch,1);}//确保读取的是数据包的第一个字节//while(ch != 0xc0)//读到的是数据包的内容,读到包尾结束{cmd[i++] = ch;read(sockfd,&ch,1);}
/***************************************数据包接收完成*****************************************************/ /******************************************解析数据包******************************************************/ //解析包长int cmd_len = cmd[0] | cmd[1]<<8 | cmd[2]<<16 | cmd[3]<<24;if(cmd_len != i){printf("read value error,the pack len is no right\n");//send_error(connfd);return;}//解析验证信息int err_no = cmd[4] | cmd[5]<<8 | cmd[6]<<16 | cmd[7]<<24;if(err_no == RESP_PACK_ERROR){printf("cmd error\n");return;}int data_len = cmd[8] | cmd[9]<<8 | cmd[10]<<16 | cmd[11]<<24;printf("recv data len:%d\n",data_len);
/*****************************************解析完毕**********************************************************/ /****************************************接收回复正文*******************************************************/memset(cmd,0,300);printf("data_len %d\n",data_len);recv(sockfd,cmd,data_len,0);printf("recv data is:%s\n",cmd);}void send_ls(int sockfd)
{/*ls 命令的数据包:0xc0 L E N S C M D S 0xc04个字节表示包的长度 4个字节表示命令*/int i = 0;int pak_len = 4+4;unsigned char cmd[50] ={0};/**********************************组合数据包***************************************************//**帧头**/cmd[i++] = 0xc0;/**包长**/cmd[i++] = pak_len & 0xff;cmd[i++] = pak_len>>8 & 0xff;cmd[i++] = pak_len>>16 & 0xff;cmd[i++] = pak_len>>24 & 0xff;/**命令**/cmd[i++] = FTP_CMD_LS & 0xff;cmd[i++] = FTP_CMD_LS>>8 & 0xff;cmd[i++] = FTP_CMD_LS>>16 & 0xff;cmd[i++] = FTP_CMD_LS>>24 & 0xff;/**帧尾**/cmd[i++] = 0xc0;
/******************************数据包组合完毕***************************************************//**发送命令**/send_cmd(sockfd,cmd,i); //将数据包发送出去后,等待服务器的处理结果/**接收返回结果**/recv_ls_val(sockfd);}void recv_get_val(int sockfd,int fd)
{/**服务器回复数据,事先会回复一个数据包0xc0 L E N S E R R N S I Z E 0xc0 回复数据包长度 回复的验证信息 后续正文大小紧接着服务器会回复正文size个字节的数据**/int i=0;unsigned char ch = 0;unsigned char cmd[300] = {0};
/*************************************接收回复数据包*******************************************************/ //命令以0xc0开头,所以如果收到的不是0xc0则舍弃不要do{//read(sockfd,&ch,1);}while(ch != 0xc0);//排除连续的0xc0while(ch == 0xc0){read(sockfd,&ch,1);}//确保读取的是数据包的第一个字节while(ch != 0xc0)//读到的是数据包的内容,读到包尾结束{cmd[i++] = ch;read(sockfd,&ch,1);}
/***************************************数据包接收完成*****************************************************/ /******************************************解析数据包******************************************************/ //解析包长int cmd_len = cmd[0] | cmd[1]<<8 | cmd[2]<<16 | cmd[3]<<24;if(cmd_len != i){printf("read value error,the pack len is no right\n");//send_error(connfd);return;}//解析验证信息int err_no = cmd[4] | cmd[5]<<8 | cmd[6]<<16 | cmd[7]<<24;if(err_no == RESP_PACK_ERROR){printf("cmd error\n");return;}int data_len = cmd[8] | cmd[9]<<8 | cmd[10]<<16 | cmd[11]<<24;printf("recv data len:%d\n",data_len);
/*****************************************解析完毕**********************************************************/ /*****************************************接收文件数据******************************************************/unsigned char *p = (unsigned char *)malloc(data_len+1);int ret=0;while(1){ret += read(sockfd,p+ret,data_len);if(ret == data_len){break;}else if(ret == -1 || ret == 0){perror("read error");return;}}write(fd,p,data_len);//将正文写入本地文件/********************************************判断文件是否发送完成*******************************************************/if(err_no == RESP_PACK_NOEND) //文件内容没有发完,会在后续发送{recv_get_val(sockfd,fd); //再次接收后续包}
}void send_get(int sockfd,char *file)
{/**get命令包格式:0xc0 L E N S C M D S S I Z E A R G S . . . . 0xc0包长(4bytes) 命令号(6bytes) 参数长度(4bytes) 参数正文(size bytes)**/int arg_len = strlen(file);int pak_len = 4 + 4 + 4 + arg_len;unsigned char cmd[50] = {0}; //保存命令数据包int i=0;
/****************************************封装命令包****************************************************//*包头*/cmd[i++] = 0Xc0;/*包长 小端模式*/cmd[i++] = pak_len & 0xff;cmd[i++] = pak_len>>8 & 0xff;cmd[i++] = pak_len>>16 & 0xff;cmd[i++] = pak_len>>24 & 0xff;/*命令号 小端模式*/cmd[i++] = FTP_CMD_GET & 0xff;cmd[i++] = FTP_CMD_GET>>8 & 0xff;cmd[i++] = FTP_CMD_GET>>16 & 0xff;cmd[i++] = FTP_CMD_GET>>24 & 0xff;/*参数长度*/cmd[i++] = arg_len & 0xff;cmd[i++] = arg_len>>8 & 0xff;cmd[i++] = arg_len>>16 & 0xff;cmd[i++] = arg_len>>24 & 0xff;/*参数正文*/int j=0;for(j=0;j<arg_len;j++){cmd[i++] = file[j];}/*包尾*/cmd[i++] = 0xc0;
/********************************************封包完成****************************************************/ /*发送命令*/send_cmd(sockfd,cmd,i);/*接收回复*/int fd = open(file,O_RDWR|O_CREAT|O_TRUNC,0777);if(-1 == fd){perror("open error");return;}recv_get_val(sockfd,fd);close(fd);
}void send_file_data1(int sockfd,int fd,int file_len)
{/*L E N S E R R N S I Z E*/unsigned char cmd[50] = {0};unsigned char buf[256] = {0};int pak_len;int size;int i;int ret = 0;while(1){size = read(fd,buf,256);if(size == 0 || size==-1){perror("read error");break;}pak_len = 4 + 4 + 4;ret += size;/*帧头*/i = 0;cmd[i++] = 0xc0;/*包长 小端模式*/cmd[i++] = pak_len & 0xff;cmd[i++] = pak_len>>8 & 0xff;cmd[i++] = pak_len>>16 & 0xff;cmd[i++] = pak_len>>24 & 0xff;/*回复码*/if(ret < file_len) //文件没完{cmd[i++] = RESP_PACK_NOEND & 0xff;cmd[i++] = RESP_PACK_NOEND>>8 & 0xff;cmd[i++] = RESP_PACK_NOEND>>16 & 0xff;cmd[i++] = RESP_PACK_NOEND>>24 & 0xff;}else{cmd[i++] = RESP_SUCCESS & 0xff;cmd[i++] = RESP_SUCCESS>>8 & 0xff;cmd[i++] = RESP_SUCCESS>>16 & 0xff;cmd[i++] = RESP_SUCCESS>>24 & 0xff;}/*正文长度*/cmd[i++] = size & 0xff;cmd[i++] = size>>8 & 0xff;cmd[i++] = size>>16 & 0xff;cmd[i++] = size>>24 & 0xff;/*帧尾*/cmd[i++] = 0xc0;send_cmd(sockfd,cmd,i); //回复数据包send(sockfd,buf,size,0); //回复正文}
} void send_put(int sockfd,char *file)
{/**get命令包格式:0xc0 L E N S C M D S S I Z E A R G S . . . . 0xc0包长(4bytes) 命令号(6bytes) 参数长度(4bytes) 参数正文(size bytes)**/int arg_len = strlen(file);int pak_len = 4 + 4 + 4 + arg_len;unsigned char cmd[50] = {0}; //保存命令数据包int i=0;
/****************************************封装命令包****************************************************//*包头*/cmd[i++] = 0Xc0;/*包长 小端模式*/cmd[i++] = pak_len & 0xff;cmd[i++] = pak_len>>8 & 0xff;cmd[i++] = pak_len>>16 & 0xff;cmd[i++] = pak_len>>24 & 0xff;/*命令号 小端模式*/cmd[i++] = FTP_CMD_PUT & 0xff;cmd[i++] = FTP_CMD_PUT>>8 & 0xff;cmd[i++] = FTP_CMD_PUT>>16 & 0xff;cmd[i++] = FTP_CMD_PUT>>24 & 0xff;/*参数长度*/cmd[i++] = arg_len & 0xff;cmd[i++] = arg_len>>8 & 0xff;cmd[i++] = arg_len>>16 & 0xff;cmd[i++] = arg_len>>24 & 0xff;/*参数正文*/int j=0;for(j=0;j<arg_len;j++){cmd[i++] = file[j];}/*包尾*/cmd[i++] = 0xc0;
/********************************************封包完成*****************************************/ /*发送命令*/send_cmd(sockfd,cmd,i);/*发送文件内容*/int fd = open(file,O_RDONLY);if(-1==fd){perror("open error");return;}int file_len = lseek(fd,0,SEEK_END); //获取文件大小lseek(fd,0,SEEK_SET);send_file_data1(sockfd,fd,file_len); //发送文件内容close(fd);}
int main(int argc,char *argv[])
{int sockfd = connect_server(argv[1],atoi(argv[2]));if(-1 == sockfd){return -1;}unsigned char cmd[5] = {0};unsigned char file[20] = {0};while(1){memset(cmd,0,5);scanf("%s",cmd);// ls <--- 查看服务器文件列表// get file <--- 从服务器获取文件列表// put file <--- 上传文件到服务器// bye <--- 告知服务器断开链接if( strcmp(cmd,"ls") == 0 ){//send_ls(sockfd);}else if(strcmp(cmd,"get")==0) // get 1.txt{scanf("%s",file);send_get(sockfd,file);}else if(strcmp(cmd,"put")==0){scanf("%s",file);send_put(sockfd,file);}}/**5.处理并退出**/close(sockfd);return 0;
}
tcp_server.c
#include <sys/types.h>
#include <sys/stat.h> /* See NOTES */
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/socket.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include "protocol.h"#define FTP_DIR "/home/gec/tftp"void send_pack(int connfd,unsigned char *cmd,int len)
{//printf("%d %x\n",connfd,cmd[0]);int ret = send(connfd,cmd,len,0);if(-1 == ret){perror("send cmd error");return;}//
}void send_error(int connfd)
{int i = 0;int pak_len = 4+4;unsigned char cmd[50] ={0};/**帧头**/cmd[i++] = 0xc0;/**包长**/cmd[i++] = pak_len & 0xff;cmd[i++] = pak_len>>8 & 0xff;cmd[i++] = pak_len>>16 & 0xff;cmd[i++] = pak_len>>24 & 0xff;/**错误码**/cmd[i++] = RESP_PACK_ERROR & 0xff;cmd[i++] = RESP_PACK_ERROR>>8 & 0xff;cmd[i++] = RESP_PACK_ERROR>>16 & 0xff;cmd[i++] = RESP_PACK_ERROR>>24 & 0xff;/**帧尾**/cmd[i++] = 0xc0;/**发送回复数据**/send_pack(connfd,cmd,i);
}void repa_ls(int connfd)
{int i = 0;int pak_len = 0;unsigned char file[500] = {0};unsigned char cmd[500] = {0};DIR *dirp = opendir(FTP_DIR);if(NULL == dirp){perror("open dir error");return ;}//struct dirent *dir;while((dir = readdir(dirp)) != NULL){sprintf(file+strlen(file),"%s ",dir->d_name);printf("%d %s\n",strlen(file),dir->d_name);}///**帧头**/cmd[i++] = 0xc0;/**包长**/pak_len = 4 + 4 + 4;cmd[i++] = pak_len & 0xff;cmd[i++] = pak_len>>8 & 0xff;cmd[i++] = pak_len>>16 & 0xff;cmd[i++] = pak_len>>24 & 0xff;/**错误码**/cmd[i++] = RESP_SUCCESS & 0xff;cmd[i++] = RESP_SUCCESS>>8 & 0xff;cmd[i++] = RESP_SUCCESS>>16 & 0xff;cmd[i++] = RESP_SUCCESS>>24 & 0xff;/**回复数据长度**/cmd[i++] = strlen(file) & 0xff;cmd[i++] = strlen(file)>>8 & 0xff;cmd[i++] = strlen(file)>>16 & 0xff;cmd[i++] = strlen(file)>>24 & 0xff;printf("recv ls data size %d\n",strlen(file));printf("%s\n",file);/**帧尾**/cmd[i++] = 0xc0;send_pack(connfd,cmd,i); //回复命令的处理结果send_pack(connfd,file,strlen(file));//回复命令数据//
}void send_file_data(int connfd,int fd,int file_len)
{/*L E N S E R R N S I Z E*/unsigned char cmd[50] = {0};unsigned char buf[256] = {0};int pak_len;int size;int i;int ret = 0;while(1){size = read(fd,buf,256);if(size == 0 || size==-1){perror("read error");break;}pak_len = 4 + 4 + 4;ret += size;/*帧头*/i = 0;cmd[i++] = 0xc0;/*包长 小端模式*/cmd[i++] = pak_len & 0xff;cmd[i++] = pak_len>>8 & 0xff;cmd[i++] = pak_len>>16 & 0xff;cmd[i++] = pak_len>>24 & 0xff;/*回复码*/if(ret < file_len) //文件没完{cmd[i++] = RESP_PACK_NOEND & 0xff;cmd[i++] = RESP_PACK_NOEND>>8 & 0xff;cmd[i++] = RESP_PACK_NOEND>>16 & 0xff;cmd[i++] = RESP_PACK_NOEND>>24 & 0xff;}else{cmd[i++] = RESP_SUCCESS & 0xff;cmd[i++] = RESP_SUCCESS>>8 & 0xff;cmd[i++] = RESP_SUCCESS>>16 & 0xff;cmd[i++] = RESP_SUCCESS>>24 & 0xff;}/*正文长度*/cmd[i++] = size & 0xff;cmd[i++] = size>>8 & 0xff;cmd[i++] = size>>16 & 0xff;cmd[i++] = size>>24 & 0xff;/*帧尾*/cmd[i++] = 0xc0;send_pack(connfd,cmd,i); //回复数据包send(connfd,buf,size,0); //回复正文}
} void repa_get(int connfd,unsigned char *cmd)
{
/************************************解析get参数*******************************************************/int i = 8;int arg_len = cmd[8] | cmd[9]<<8 | cmd[10]<<16 | cmd[11]<<24;char *file = (char *)malloc(arg_len+1);memset(file,0,arg_len+1);for(i=0;i<arg_len;i++){file[i] = cmd[12+i]; //获取文件名}/************************************打开文件读取数据并准备回复************************************************/int pak_len = 0;i=0;char ftp_file[100] = {0};sprintf(ftp_file,"%s/%s",FTP_DIR,file);int fd = open(ftp_file,O_RDONLY);if(-1 == fd){perror("open error");/*帧头*/cmd[i++] = 0xc0;pak_len = 8;/*包长 小端模式*/cmd[i++] = pak_len & 0xff;cmd[i++] = pak_len>>8 & 0xff;cmd[i++] = pak_len>>16 & 0xff;cmd[i++] = pak_len>>24 & 0xff;/*回复码*/cmd[i++] = RESP_PACK_NOFILE & 0xff;cmd[i++] = RESP_PACK_NOFILE>>8 & 0xff;cmd[i++] = RESP_PACK_NOFILE>>16 & 0xff;cmd[i++] = RESP_PACK_NOFILE>>24 & 0xff;/*帧尾*/cmd[i++] = 0xc0;send_pack(connfd,cmd,i);}else{int file_len = lseek(fd,0,SEEK_END); //获取文件大小lseek(fd,0,SEEK_SET);send_file_data(connfd,fd,file_len); //回复文件内容close(fd);}}
void recv_get_val1(int connfd,int fd)
{/**服务器回复数据,事先会回复一个数据包0xc0 L E N S E R R N S I Z E 0xc0 回复数据包长度 回复的验证信息 后续正文大小紧接着服务器会回复正文size个字节的数据**/int i=0;unsigned char ch = 0;unsigned char cmd[300] = {0};
/*************************************接收回复数据包*******************************************************/ //命令以0xc0开头,所以如果收到的不是0xc0则舍弃不要do{//read(connfd,&ch,1);}while(ch != 0xc0);//排除连续的0xc0while(ch == 0xc0){read(connfd,&ch,1);}//确保读取的是数据包的第一个字节while(ch != 0xc0)//读到的是数据包的内容,读到包尾结束{cmd[i++] = ch;read(connfd,&ch,1);}
/***************************************数据包接收完成*****************************************************/ /******************************************解析数据包******************************************************/ //解析包长int cmd_len = cmd[0] | cmd[1]<<8 | cmd[2]<<16 | cmd[3]<<24;if(cmd_len != i){printf("read value error,the pack len is no right\n");//send_error(connfd);return;}//解析验证信息int err_no = cmd[4] | cmd[5]<<8 | cmd[6]<<16 | cmd[7]<<24;if(err_no == RESP_PACK_ERROR){printf("cmd error\n");return;}int data_len = cmd[8] | cmd[9]<<8 | cmd[10]<<16 | cmd[11]<<24;printf("recv data len:%d\n",data_len);
/*****************************************解析完毕**********************************************************/ /*****************************************接收文件数据******************************************************/unsigned char *p = (unsigned char *)malloc(data_len+1);int ret=0;while(1){ret += read(connfd,p+ret,data_len);if(ret == data_len){break;}else if(ret == -1 || ret == 0){perror("read error");return;}}write(fd,p,data_len);//将正文写入本地文件/********************************************判断文件是否发送完成*******************************************************/if(err_no == RESP_PACK_NOEND) //文件内容没有发完,会在后续发送{recv_get_val1(connfd,fd); //再次接收后续包}}void repa_put(int connfd,unsigned char *cmd)
{int i = 8;int arg_len = cmd[8] | cmd[9]<<8 | cmd[10]<<16 | cmd[11]<<24;char *file = (char *)malloc(arg_len+1);memset(file,0,arg_len+1);for(i=0;i<arg_len;i++){file[i] = cmd[12+i]; //获取文件名}char ftp_file[100] = {0};sprintf(ftp_file,"%s/%s",FTP_DIR,file);int fd = open(ftp_file,O_RDWR|O_CREAT|O_TRUNC,0777);if(-1 == fd){perror("open error");return;}recv_get_val1(connfd, fd);}
int recv_cmd(int connfd)
{int i=0;unsigned char ch = 0;unsigned char cmd[50] = {0};while(1){//命令以0xc0开头,所以如果收到的不是0xc0则舍弃不要do{read(connfd,&ch,1);}while(ch != 0xc0);//排除连续的0xc0while(ch == 0xc0){read(connfd,&ch,1);}//确保读取的是数据包的第一个字节i=0;while(ch != 0xc0)//读到的是数据包的内容,读到包尾结束{cmd[i++] = ch;read(connfd,&ch,1);}int cmd_len = cmd[0] | cmd[1]<<8 | cmd[2]<<16 | cmd[3]<<24;if(cmd_len != i){printf("read cmd error,the pack len is no right\n");send_error(connfd);return 0;}int cmd_num = cmd[4] | cmd[5]<<8 | cmd[6]<<16 | cmd[7]<<24;switch(cmd_num)//判断收到的命令{case FTP_CMD_LS:repa_ls(connfd);break;case FTP_CMD_GET: repa_get(connfd,cmd);break;case FTP_CMD_PUT: repa_put(connfd,cmd);break;}}
}int main(int argc,char *argv[])
{
/**1.创建套接字**/int sockfd = socket(AF_INET,//IPv4协议族SOCK_STREAM,//流式套接字0//默认协议);if(-1 == sockfd){perror("socket error");return -1;}/**设置套接字选项**/int val = 1;setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&val,4);//允许地址重用setsockopt(sockfd,SOL_SOCKET,SO_REUSEPORT,&val,4);//允许端口重用
/**2.绑定地址**/struct sockaddr_in sAddr;//以太网协议地址结构体 <--- 方便赋值memset(&sAddr,0,sizeof(sAddr));sAddr.sin_family = AF_INET;//协议族sAddr.sin_port = htons(atoi(argv[2]));//网络字节序的短整型sAddr.sin_addr.s_addr =inet_addr(argv[1]);//网络字节序的u32整数int ret;ret = bind(sockfd,//绑定的套接字(struct sockaddr*)&sAddr,//该套接字绑定的"地址"sizeof(sAddr)//地址长度);//将套接字与"地址"绑定if(-1 == ret){perror("bind error");return -1;}/**3.设置监听**/ret = listen(sockfd,10);if(-1 == ret){perror("listen error");return -1;}/**4.等待链接**/int connfd;struct sockaddr_in cAddr;socklen_t addrlen = sizeof(cAddr);while(1){connfd = accept(sockfd,//套接字描述符,表示等待那个套接字上的链接(struct sockaddr*)&cAddr,//"地址"空间,用来保存客户端的地址&addrlen//空间,用来保存客户端地址长度);//如果有客户端链接,服务器端接受请求并返回链接描述符//链接描述符是用来与 对应的客户端进行通信if(-1 == connfd){perror("accept error");return -1;}printf("connect client is:%s:%d\n",inet_ntoa(cAddr.sin_addr),ntohs(cAddr.sin_port));pid_t pid = fork();if(pid > 0){close(connfd);continue;}else if(pid == 0){//recv_cmd(connfd);exit(0);}}
/**7.处理并退出**/ close(sockfd);close(connfd);return 0;
}
Linux网络编程——基于tcp/ip的模拟聊天(文件传输)工具相关推荐
- 两台linux电脑在互联网内传输文件,linux网络编程之实现跨平台PC之间进行文件传输...
//实现两台计算机进行文件传输,包括跨平台传输即linux与windows之间 //TCP的文件传输 //文件大小不限制,需要做到将大文件分包去做 server.c //服务端程序 int main( ...
- 网络编程——基于TCP协议的通讯录【课程设计】
网络编程--基于TCP协议的通讯录[课程设计] 本文目录 网络编程--基于TCP协议的通讯录[课程设计] 一.设计题目和要求 设计目标: 课程设计系统组成及模块功能: 二.设计内容 服务端 客户端 S ...
- 【Linux网络编程】TCP带外数据
[Linux网络编程]TCP带外数据 [1]TCP 包的部首 TCP带外数据相关概念 紧急字段URG : 当URG=1时,告诉系统此报文段中有紧急数据,应尽快传送. 紧急指针 ...
- 项目实战:基于 TCP 的局域网内高性能文件传输系统设计与实现
本项目开发基于 Red Hat Enterprise Linux(RHEL) 6.3 平台 ,通过本项目大家会深入理解下述内容: Socket 网络编程技术 基于TCP/IP 协议的网络编程技术 基于 ...
- QT从入门到入土(九)——TCP/IP网络通信(以及文件传输)
引言 TCP/IP通信(即SOCKET通信)是通过网线将服务器Server端和客户机Client端进行连接,在遵循ISO/OSI模型的四层层级构架的基础上通过TCP/IP协议建立的通讯.控制器可以设置 ...
- 【Linux网络编程】TCP编程
00. 目录 文章目录 00. 目录 01. TCP概述 02. TCP特点 03. TCP中CS架构 04. TCP相关函数 05. TCP服务端示例 06. TCP客户端示例 07. 附录 01. ...
- 【Linux网络编程】TCP三次握手和四次挥手
00. 目录 文章目录 00. 目录 01. 三次握手 02. 四次挥手 03. 三次握手和四次挥手原因 04. 2MSL 05. 附录 01. 三次握手 在 TCP/IP 协议中,TCP 协议提供可 ...
- 【Linux网络编程】TCP网络编程中connect listen和accept三者之间的关系
00. 目录 文章目录 00. 目录 01. TCP服务端和客户端流程 02. connect函数 03. listen函数 04. 三次握手 05. accept函数 06. 附录 01. TCP服 ...
- step5 . day6 网络编程 基于TCP协议的多并发模式(使用多进程、多线程、select函数分别实现)...
实现TCP服务器端多路并发的方法有①多进程②多线程③IO多路复用(select poll epoll函数) 1.多进程实现并发模式(仅在服务器端更改之前代码实现) 服务器端 #include < ...
最新文章
- FastDFS之Linux下搭建
- linux-----shell高级编程----grep应用
- Windows Vista for Developers——第三部分补充:控件和桌面窗口管理器
- SQLSERVER常用函数汇总
- python处理excel案例_python操作excel例子
- Python数据存储:pickle模块的使用讲解(测试代码)
- 人工智能大脑如何调控智能交通“疏堵”?
- 保留12位小数的浮点数(信息学奥赛一本通-T1025)
- android启动界面修改工具,Android 系统界面调节工具使用及功能
- 招聘云计算、虚拟化、前端开发、测试等工程师
- linux mysql 开发_Linux64下mysql安装和开发
- Java的测试方法有哪些?自动化测试让Java测试变得更简单!
- PaddleOCR 手写识别模型:标注到训练
- 在windows系统下制作虚拟软驱
- 小白莲的操作系统day05-2.3(01-05)
- VC写的双人版俄罗斯方块
- Selective Search算法-候选框生成
- 用100元换10元、5元和1元的纸币共50张,能换各种纸币多少张。
- 速途研究院联合融云:中国移动社交沟通指数报告
- Python实现undo操作