Linux系统下通过TCP可下载文件的客户端、服务端
程序员文章站
2022-03-04 08:53:50
...
这是运行与Linux系统下的多线程并发服务器,可供多个客服端下载普通文件,大型MP3/MP4等文件。
功能通过终端命令进行操作
client端代码:
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/stat.h>
#include <fcntl.h>
//./clt ip
int main(int argc, char ** argv)
{
int ret ;
int sfd;
int fd;
char buf[1024] = {0};
char filebuf[1024]={0};
char buf1[20]={0};
sfd = socket(AF_INET, SOCK_STREAM, 0);
if(ret < 0) {
perror("socket");
return -1;
}
struct sockaddr_in s_addr;
memset(&s_addr, 0, sizeof(s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(8888); //服务器端口号,要转换成网络字节序
s_addr.sin_addr.s_addr = inet_addr(argv[1]); //服务器地址, 要转换成网络字节序
//连接服务器
ret = connect (sfd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr));
if(ret < 0) {
perror("socket");
return -1;
}
char input[100];
while(1) {
printf("please input data:\r\n");
ret = read(0, input, 50);
if(ret < 0) {
perror("send");
return -1;
}
input[ret-1] = '\0';
//发送数据给客户端
ret = send(sfd, input, strlen(input), 0);
if(ret < 0) {
perror("send");
return -1;
}
memset(filebuf,0,sizeof(filebuf));
strcat(filebuf,"./");
strcat(filebuf,input);
printf("%s\r\n",filebuf);
fd = open(filebuf, O_WRONLY | O_APPEND | O_CREAT, 0666);//
if(fd<0)
{
perror("open");
}
while(1)
{
memset(buf,0,1024);
//接收数据,如果客户端没有发送数据会阻塞在这里
ret = recv(sfd, buf, 1024, 0);
if(ret < 0 ) {
perror("recv ");
return -1;
}
if(ret == 0) {
printf("child thread tid==%lu exit\r\n", pthread_self());
break;
}
buf[ret]='\0';
if(memcmp(buf,"ok",2)==0)
{
printf("------download finshed----\r\n");
break;
}
write(fd, buf, 1024);
memset(buf,0,1024);
}
close(fd);
}
close(sfd);
return 0;
}
service端带代码:
//多线程并发服务器
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
struct server_info {
int cfd; //通信套接字
struct sockaddr_in c_addr; //存放客户端地址
};
void * function(void*arg) ;
int main(int argc, char ** argv)
{
int ret ;
int sfd, cfd;
pthread_t tid; //线程id
sfd = socket(AF_INET, SOCK_STREAM, 0);
if(ret < 0) {
perror("socket");
return -1;
}
//让服务器断开后重启连接不会报地址被占用的错误
int reuse = 1;
ret = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
struct sockaddr_in s_addr;
memset(&s_addr, 0, sizeof(s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(8888); //服务器端口号,要转换成网络字节序
//s_addr.sin_addr.s_addr = inet_addr("192.168.1.123");//服务器地址, 要转换成网络字节序
s_addr.sin_addr.s_addr = 0; //服务器一般填充0,这样程序可以任意IP的计算中运行。
ret = bind(sfd, ( struct sockaddr*)&s_addr, sizeof(struct sockaddr));
if(ret < 0) {
perror("bind");
return -1;
}
ret = listen(sfd, 10);
if(ret < 0) {
perror("listen");
return -1;
}
struct sockaddr_in c_addr;
int addrlen;
memset(&c_addr, 0, sizeof(c_addr));
while(1) {
//等待连接
cfd = accept(sfd, (struct sockaddr*)&c_addr, &addrlen);
if(cfd < 0) {
perror("accept ");
return -1;
}
//创建线程独立数据结构空间
//每个线程应该有独立的cfd,c_add结构,malloc是在堆空间中分配数据
struct server_info *tinfo = malloc(sizeof(struct server_info));
memset(tinfo, 0, sizeof( struct server_info));
tinfo->cfd = cfd;
tinfo->c_addr = c_addr;
ret = pthread_create(&tid, NULL, function, (void*)tinfo) ; //创建线程
if(ret != 0) {
perror("pthread_create ");
free(tinfo);
return -1;
}
}
close(sfd);
return 0;
}
//写一个线程函数
//假设传递进来是 struct server_info * ,则把arg转换回来
void * function(void*arg)
{
int ret;
int fd;
int fr;
char buf[1025] = {0};
char filebuf[1024]={0};
char fbuf[]={"ok"};
//int fbuf[1]={52};
struct server_info * info = ( struct server_info *)arg;
pthread_detach(pthread_self()); //把本线程变成分离式线程
//char *inet_ntoa(struct in_addr in);
printf("One client is connected:ip:%s:%d\r\n",
inet_ntoa(info->c_addr.sin_addr), ntohs(info->c_addr.sin_port));
while(1) {
//接收数据,如果客户端没有发送数据会阻塞在这里
printf("=========\r\n");
ret = recv(info->cfd, buf, 100, 0);
if(ret < 0) {
perror("recv ");
break;
}
//ret==0;说明连接已经断开,子进程 要终止
if(ret == 0) {
printf("child thread tid==%lu exit\r\n", pthread_self());
//资源释放
close(info->cfd);
free(info);
pthread_exit(NULL);
}
buf[ret] = '\0';
printf("C---> S : %s \r\n", buf);
memset(filebuf,0,sizeof(filebuf));
strcat(filebuf,"./");
strcat(filebuf,buf);
//strcat(filebuf,".mp3");
//strcat(filebuf,".txt");
printf("%s\r\n",filebuf);
fd = open(filebuf, O_RDONLY);
if(fd<0)
{
perror("open");
}
while(1)
{
memset(buf,0,1024);
fr=read(fd, buf, 1024);
if(fr==0)
{
printf("file read over\r\n");
sleep(1);//不加延时会不能跳出来
ret = send(info->cfd, fbuf, 2, 0);
//printf("%d\r\n",strlen(fbuf));
if(ret < 0) {
perror("send");
break;
}
break;
}
else
{
//发送数据给客户端
ret = send(info->cfd, buf, fr, 0);
if(ret < 0) {
perror("send");
break;
}
}
}
//perror("open------------------");
close(fd);
}
//资源释放
close(info->cfd);
free(info);
pthread_exit(NULL);
}