#網絡程序設計#實驗二:利用TCP完成文件傳輸的設計和實現

更多網絡程序設計的文章見:目錄

實驗目的

  • 輸入文件路徑,利用TCP實現客戶文件向服務器的傳輸,並實現TCP的基本封裝

實驗原理

  • 服務器
    (1) 建立 socket
    (2) 確定服務器 scokaddr_in 結構體
    (3)點分十進制 IP 轉換
    (4)使用 bind 綁定套接字
    (5)使用 listen 監聽
    (6)使用 accept 接受連接請求
    (7)accept 返回新的套接字描述符
    (8)使用 recv 接收傳來的數據(文件路徑)
    (9)打開文件,這裏需要文件名
    (10)從該字符串獲取文件名
    (11)使用 recv 接收文件內容
    (12)判斷 recv 函數返回的狀態
    (13)將接收到的內容放入緩衝區
    (14)將緩衝區內容寫入文件
    (15)關閉文件
    (16)關閉 socket
  • 客戶端
    (1)建立 socket
    (2)確定服務器 scokaddr_in 結構體
    (3)點分十進制 IP 轉換
    (4)使用 connect 連接
    (5)打開文件
    (6)準備緩衝區
    (7)緩衝區初始化置空
    (8)將文件內容讀入緩衝區
    (9)使用 send 將緩衝區內容發送到服務器
    (10)文件內容發送完成(11)關閉文件
    (12)關閉 socket

實驗內容

  • 服務器端
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <netdb.h>
#include <string.h>
 
#define ERR_EXIT(m)				\
	do					\
	{					\
		perror(m);			\
		exit(EXIT_FAILURE);		\
	}while(0)
 
int passiveTCP()
{
	int listenfd;//創建一個套接字
	if((listenfd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
	{
		ERR_EXIT("socket");
	}

	struct sockaddr_in servaddr;
	memset(&servaddr,0,sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(5188);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);	
	
	if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
	{
		ERR_EXIT("bind");
	}
	
	if(listen(listenfd,SOMAXCONN) < 0)
		ERR_EXIT("listen");

	return listenfd;
}

int main()
{
	int fd = passiveTCP();
	char filename[100];
	char buffer[1024];

	while(1)
	{
		int conn;
		struct sockaddr_in peeraddr;
		socklen_t peerlen = sizeof(peeraddr);
		if((conn = accept(fd,(struct sockaddr*)&peeraddr,&peerlen)) < 0)
			ERR_EXIT("accept");
		else
		{
			printf("connect success\n");
			recv(conn, filename, sizeof(filename), 0);
			FILE *fp = fopen(filename, "w");
			printf("transport start\n");
			int t;
			while((t = recv(conn, buffer, 1024, 0)) > 0)
			{
				fwrite(buffer, sizeof(char), t, fp);
			}
			printf("transport finish\n");
			fclose(fp);
		}
		close(conn);
	}
	close(fd);
	return 0;
}
  • 客戶端
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
#define ERR_EXIT(m)				\
	do					\
	{					\
		perror(m);			\
		exit(EXIT_FAILURE);		\
	}while(0)
 
int main()
{
	int sock;
	if((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
	{
		ERR_EXIT("socket");
	}
	
	struct sockaddr_in servaddr;
	memset(&servaddr,0,sizeof(servaddr));
	servaddr.sin_family = AF_INET;	
	servaddr.sin_port = htons(5188);
	servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	
	char filename [100];
	char buffer[1024];

	if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
		printf("error\n");
	else
	{
		printf("success\n");
		printf("input filename:\n");
		scanf("%s", filename);
		FILE* fp = fopen(filename, "r");
		if(fp == NULL)
			printf("file not exist\n");
		else
		{
			printf("transport start\n");
			send(sock, filename, sizeof(filename), 0);
			int t;
			while((t = fread(buffer, sizeof(char), 1024, fp)) > 0)
				send(sock, buffer, t, 0);
			printf("transport finish\n");
		}
		fclose(fp);
	}

	close(sock);
	return 0;
}

實驗結果

  • 傳輸前客戶端根目錄下保存着文件1.txt
    在這裏插入圖片描述
  • 服務器根目錄下沒有這個文件
    在這裏插入圖片描述
  • 傳輸開始
    在這裏插入圖片描述
  • 傳輸完成後,服務器根目錄下出現1.txt,傳輸成功
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章