Linux下基于socket的文件传输程序设计讲解
跨平台(Windows+Linux)的Socket通讯程序(一)—底层封装(转)

跨平台(Windows+Linux)的Socket通讯程序(一)—底层封装(转)【摘要】编写Socket通讯程序是一个老话题。
本文重点介绍Windows平台和Linux平台Socket通讯的不同,采用C++,编制了一个简单的跨平台的Socket通讯库。
一、Socket通讯的基础知识Socket通讯是两个计算机之间最基本的通讯方法,有TCP和UDP 两种协议。
关于这两种协议的区别,不少文章已有详述,这里,稍微总结一下:1.TCP是面向连接的,是“流”式的,意即通讯两端建立了一个“数码流管”,该流无头无尾,接收端保证接收顺序,但不保证包的分割。
2.UDP是面向无连接的,是“包”式的,意即通讯两端自由发送数据包,接收端不保证接收顺序,但保证包的分割与发送端一致。
正是基于上述二者的不同,在编程上,它们的区别如下:对TCP 连接,服务器端过程(bind->listen->accept->send/receive)与客户端不相同(connect->send/receive),对UDP连接,二者似乎更对等一些(服务器端仅需要bind)。
二、socket在windows下和linux下的区别一些文章也已涉及,这里,也是综合一下,并加上自己的理解。
三、跨平台的Socket辅助程序以下给出源代码。
sock_wrap.h代码如下,其中用到了platform.h,定义_WIN32_PLATFROM_和_LINUX_PLATFROM_两个宏。
[cpp]view plaincopy1.#ifndef _SOCK_WRAP_H_2.#define _SOCK_WRAP_H_3.4.#include "platform.h"5.6.#if defined(_WIN32_PLATFROM_)7.#include <winsock2.h>8.typedef SOCKET HSocket;9.#endif10.11.#if defined(_LINUX_PLATFORM_)12.#include <netinet/in.h>13.#include <sys/socket.h>14.#include <sys/types.h>15.16.typedef int HSocket;17.#define SOCKET_ERROR (-1)18.#define INVALID_SOCKET 019.#endif20.21.22.typedef struct23.{24.int block;25.int sendbuffersize;26.int recvbuffersize;27.int lingertimeout;28.int recvtimeout;29.int sendtimeout;30.} socketoption_t;31.32.typedef struct33.{34.int nbytes;35.int nresult;36.} transresult_t;37.38.int InitializeSocketEnvironment();39.void FreeSocketEnvironment();40.void GetAddressFrom(sockaddr_in *addr, const char *i p, int port);41.void GetIpAddress(char *ip, sockaddr_in *addr);42.bool IsValidSocketHandle(HSocket handle);43.int GetLastSocketError();44.45.HSocket SocketOpen(int tcpudp);46.void SocketClose(HSocket &handle);47.48.int SocketBlock(HSocket hs, bool bblock);49.int SocketTimeOut(HSocket hs, int recvtimeout, int sen dtimeout, int lingertimeout);50.51.int SocketBind(HSocket hs, sockaddr_in *addr);52.HSocket SocketAccept(HSocket hs, sockaddr_in *addr) ;53.int SocketListen(HSocket hs, int maxconn);54.55.void SocketSend(HSocket hs, const char *ptr, int nbyte s, transresult_t &rt);56.void SocketRecv(HSocket hs, char *ptr, int nbytes, tran sresult_t &rt);57.void SocketTryRecv(HSocket hs, char *ptr, int nbytes, i nt milliseconds, transresult_t &rt);58.void SocketTrySend(HSocket hs, const char *ptr, int nb ytes, int milliseconds, transresult_t &rt);59.60.void SocketClearRecvBuffer(HSocket hs);61.62.class CSockWrap63.{64.public:65.CSockWrap(int tcpudp);66.~CSockWrap();67.void SetAddress(const char *ip, int port);68.void SetAddress(sockaddr_in *addr);69.int SetTimeOut(int recvtimeout, int sendtimeout, int li ngertimeout);70.int SetBufferSize(int recvbuffersize, int sendbuffersize);71.int SetBlock(bool bblock);72.73.HSocket GetHandle () { return m_hSocket;}74.void Reopen(bool bForceClose);75.void Close();76.transresult_t Send(void *ptr, int nbytes);77.transresult_t Recv(void *ptr, int nbytes );78.transresult_t TrySend(void *ptr, int nbytes, int milliseco nds);79.transresult_t TryRecv(void *ptr, int nbytes, int milliseco nds );80.void ClearRecvBuffer();81.82.protected:83.HSocket m_hSocket;84.sockaddr_in m_stAddr;85.int m_tcpudp;86.};87.88.89.#endifsock_wrap.cpp代码如下,其中引用了lightThread.h和spantime.h,它们的代码见“跨平台(Windows+Linux)的线程辅助程序”。
socket传输文件的原理

socket传输文件的原理
文件传输是计算机网络中的一项基本功能,它允许在网络上的不同计算机之间共享和传输文件。
Socket是实现文件传输的一种常用方式,其原理如下:
1. 建立连接:在进行文件传输之前,需要在发送方和接收方之间建立连接。
这通常通过TCP/IP 协议实现,使用Socket进行连接的建立。
一旦连接建立成功,发送方和接收方就可以通过该连接进行数据传输。
2. 文件分割:由于文件通常较大,不适合一次性传输,因此需要将文件分割成较小的数据块。
这些数据块可以按照一定的顺序进行编号,以便于接收方重新组合成完整的文件。
3. 发送数据:发送方通过Socket将分割好的数据块逐个发送给接收方。
在发送数据时,需要按照一定的协议进行数据的封装,例如添加文件名、数据块大小等信息。
4. 接收数据:接收方通过Socket接收到数据后,需要按照发送方的协议对数据进行解析和处理。
接收方会将收到的数据块进行缓存,以便后续重新组合成完整的文件。
5. 确认机制:为了确保文件传输的完整性和正确性,发送方和接收方之间需要建立一种确认机制。
例如,发送方可以发送一个数据包的编号给接收方,接收方在收到数据包后回复一个确认信号给发送方,表示该数据包已经成功接收。
如果发送方在一定时间内没有收到确认信号,则会重新发送数据包,以确保数据的可靠传输。
6. 关闭连接:当文件传输完成后,发送方和接收方之间的连接会被关闭。
这可以通过Socket 的关闭函数实现,释放网络资源。
通过以上步骤,使用Socket可以实现文件的传输。
在实际应用中,不同的文件传输协议可能会有一些差异,但基本原理是相同的。
C语言基于socket的文件传输(可循环发送多个文件)

C语⾔基于socket的⽂件传输(可循环发送多个⽂件)基本简介:本次⽂件传输的实现主要是通过客户端向服务器发送下载请求,然后在服务器中找到对应的⽂件并打开⽂件,再继续向客户端传送⽂件,⽽客户端就在不停的接收。
这是因为⽂件可能⽐较⼤,⼀个缓冲数组只能保存⼀部分⽂件内容,因此服务器得不断从⽂件中读取内容并发给客户端,⽽客户端得不停的循环接收。
但是在事先,得将相应要发送的⽂件(照⽚,⾳频,视频等)保存在服务器相应的⽬录下。
⽽这个是不符合实际要求的,通常来讲,是应该将客户端1的⽂件发送给客户端2,⽽服务器仅仅只是起到⼀个中转站的作⽤,即⽂件应该事先保存在客户端1下。
这⾥我们只是完成⽂件传输的相应功能就⾏了,就不在计较这些啦。
因为只要你理解了这⼀块,可以根据⾃⼰的实际需要,在进⾏修改。
具体编译:gcc server.c -o server -lpthread //这是因为在服务器中加⼊了线程函数,所以编译的时候需要加上 -lpthread 。
gcc client.c -o client记住⼀定要先运⾏服务器,在运⾏客户端。
在客户端运⾏的时候回提醒你输⼊服务器对应的pc ip,如实输⼊就⾏啦。
如果是在本机pc上进⾏测试的话,也可以输⼊0.0.0.0 。
server.c:#include <stdio.h>#include <netdb.h>#include <sys/socket.h>#include <arpa/inet.h>#include <sys/types.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <netinet/in.h>#include <pthread.h>#define portnum 12345#define FILE_SIZE 500#define BUFFER_SIZE 1024void *net_thread(void * fd);int main(){//初始化套接字int server_fd=socket(AF_INET,SOCK_STREAM,0);if(-1==server_fd){perror("socket");exit(1);}//绑定端⼝和ip;struct sockaddr_in server_addr; //struct sockaddr_in为结构体类型,server_addr为定义的结构体server_addr.sin_family=AF_INET; //Internet地址族=AF_INET(IPv4协议)server_addr.sin_port=htons(portnum); //将主机字节序转化为⽹络字节序 ,portnum是端⼝号(server_addr.sin_addr).s_addr=htonl(INADDR_ANY);//IP地址if(-1==bind(server_fd,(struct sockaddr *)&server_addr,sizeof(server_addr))) //套接字与端⼝绑定{perror("bind");exit(6);}//开启监听if(-1==listen(server_fd,5)) //5是最⼤连接数,指服务器最多连接5个⽤户if(-1==listen(server_fd,5)) //5是最⼤连接数,指服务器最多连接5个⽤户{perror("listen");exit(7);}while(1){struct sockaddr_in client_addr;int size=sizeof(client_addr);int new_fd=accept(server_fd,(struct sockaddr *)&client_addr,&size); //server_fd服务器的socket描述字,&client_addr指向struct sockaddr *的指针,&size指向协议地址if(-1==new_fd){perror("accept");continue; //进⾏下⼀次循环}printf("accept client ip:%s:%d\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port);//inet_ntoa将⼀个⼗进制⽹络字节序转换为点分⼗进制IP格式的字符串。
Linux的SOCKET编程详解

Linux的SOCKET编程详解1. 网络中进程之间如何通信进程通信的概念最初来源于单机系统。
由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进程之间既互不干扰又协调一致工作,操作系统为进程通信提供了相应设施,如UNIX BSD有:管道(pipe)、命名管道(named pipe)软中断信号(signal)UNIX system V有:消息(message)、共享存储区(shared memory)和信号量(semaphore)等.他们都仅限于用在本机进程之间通信。
网间进程通信要解决的是不同主机进程间的相互通信问题(可把同机进程通信看作是其中的特例)。
为此,首先要解决的是网间进程标识问题。
同一主机上,不同进程可用进程号(process ID)唯一标识。
但在网络环境下,各主机独立分配的进程号不能唯一标识该进程。
例如,主机A赋于某进程号5,在B机中也可以存在5号进程,因此,“5号进程”这句话就没有意义了。
其次,操作系统支持的网络协议众多,不同协议的工作方式不同,地址格式也不同。
因此,网间进程通信还要解决多重协议的识别问题。
其实TCP/IP协议族已经帮我们解决了这个问题,网络层的―ip地址‖可以唯一标识网络中的主机,而传输层的―协议+端口‖可以唯一标识主机中的应用程序(进程)。
这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。
使用TCP/IP协议的应用程序通常采用应用编程接口:UNIX BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰),来实现网络进程之间的通信。
就目前而言,几乎所有的应用程序都是采用socket,而现在又是网络时代,网络中进程通信是无处不在,这就是我为什么说―一切皆s ocket‖。
TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。
利用socket进行数据通信与传输的步骤

利用socket进行数据通信与传输的步骤Socket是计算机之间进行数据传输和通信的标准接口。
利用Socket可以方便地进行网络编程,实现不同设备之间的数据交换和传输。
下面将介绍Socket进行数据通信和传输的步骤,以及一些注意事项。
1. 创建Socket连接首先,需要在客户端和服务器端分别创建Socket连接。
在客户端,可以使用socket.connect()方法;在服务器端,可以使用socket.bind()方法。
这些方法都需要指定IP地址和端口号,以确保连接成功。
2. 发送数据一旦连接成功,就可以开始发送数据。
在Python中,可以使用socket.send()方法发送数据。
这个方法需要传入一个字符串参数,表示要发送的数据。
如果要发送二进制数据,则需要使用socket.sendall()方法。
这个方法需要传入一个字节串参数。
3. 接收数据一旦数据发送成功,服务器端就可以接收到这些数据。
在Python 中,可以使用socket.recv()方法接收数据。
这个方法需要传入一个整数参数,表示要接收的数据大小。
如果数据不足这个大小,则该方法会阻塞,等待更多数据到达。
4. 处理数据一旦接收到数据,就需要对这些数据进行处理。
这通常包括解析数据、验证数据、存储数据等操作,以确保数据的正确性和完整性。
5. 关闭连接最后,需要在客户端和服务器端分别关闭Socket连接。
在Python 中,可以使用socket.close()方法关闭连接。
这个方法不需要传入任何参数,只需要调用即可。
在进行Socket编程时,还需要注意一些事项。
比如,需要指定协议类型(如TCP或UDP)、设置超时时间、处理异常等。
此外,还需要考虑数据安全性和加密性等问题,以确保数据在传输过程中不会被恶意攻击者窃取或篡改。
总之,Socket编程是实现计算机间数据通信和传输的重要方法,可以应用于各种场景,如互联网、物联网、机器人等领域。
在使用Socket时,需要严格遵循以上步骤和注意事项,以确保数据的正确传输和保密性。
socket数据传输原理

socket数据传输原理在计算机网络中,Socket是网络通信的一种机制,它用于在不同的主机之间传输数据。
Socket数据传输原理可以分为以下几个步骤:1.建立连接:客户端与服务器之间通过Socket建立连接。
客户端通过调用Socket库函数创建一个Socket对象,并指定服务器的IP地址和端口号。
服务器通过调用Socket库函数创建一个Socket对象,并绑定到一个指定的IP地址和端口号上。
当客户端向服务器发起连接请求时,服务器会接收到该连接请求,并返回一个表示连接已建立的Socket对象。
2.数据读写:一旦连接建立,客户端和服务器可以通过各自的Socket对象进行数据读写操作。
客户端可以向服务器发送数据,服务器可以接收数据并进行处理;服务器可以向客户端发送数据,客户端可以接收数据并进行处理。
这些数据可以是文本、图片、音视频等任意类型的数据。
3.数据分片传输:当数据传输量较大时,Socket会将数据分成多个较小的数据包进行传输。
这样可以避免网络拥塞和数据丢失的问题。
发送方将数据分片并打包成数据包,然后依次发送给接收方。
接收方在接收到数据包后进行解包,恢复原始数据。
4.数据确认和重传:在数据传输过程中,接收方会向发送方发送一个确认消息,表示已成功接收到数据。
如果发送方没有收到接收方的确认消息,或者接收方接收到的数据包有误,发送方会根据一定的策略进行重传,以确保数据的可靠传输。
5.连接关闭:当数据传输完成或者不再需要进行数据传输时,客户端和服务器可以通过调用Socket对象的关闭方法来关闭连接。
关闭连接后,客户端和服务器将无法进行数据传输。
总体而言,Socket数据传输原理是通过建立连接、数据读写、数据分片传输、数据确认和重传以及连接关闭等步骤来实现数据在网络中的传输。
Linux下C语言的socket函数解析

Linux下C语言的socket函数解析socketsocket()我们使用系统调用socket()来获得文件描述符:#include#includeint socket(int domain,int type,int protocol);第一个参数domain设置为“AF_INET”。
第二个参数是套接口的类型:SOCK_STREAM或SOCK_DGRAM。
第三个参数设置为0。
系统调用socket()只返回一个套接口描述符,如果出错,则返回-1。
bind()一旦你有了一个套接口以后,下一步就是把套接口绑定到本地计算机的某一个端口上。
但如果你只想使用connect()则无此必要。
下面是系统调用bind()的使用方法:#include#includeintbind(int sockfd,struct sockaddr*my_addr,int addrlen);第一个参数sockfd是由socket()调用返回的套接口文件描述符。
第二个参数my_addr是指向数据结构sockaddr的指针。
数据结构sockaddr中包括了关于你的地址、端口和IP地址的信息。
第三个参数addrlen可以设置成sizeof(structsockaddr)。
下面是一个例子:#include#include#include#define MYPORT 3490main(){int sockfd;struct sockaddr_inmy_addr;sockfd=socket(AF_INET,SOCK_STREAM,0);/*do someerror checking!*/my_addr.sin_family=AF_INET;/*hostbyteorder*/my_addr.sin_port=htons(MYPORT);/*short,network byte order*/my_addr.sin_addr.s_addr=inet_addr("132.241.5.10");bzero(&(my_addr.sin_zero),8);/*zero the rest of the struct*//*don't forget your error checking for bind():*/bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));...如果出错,bind()也返回-1。
linux socket 内核原理

Linux中的Socket是一种用于网络通信的编程接口,它允许进程通过网络进行数据传输。
Socket在Linux内核中的实现涉及到多个组件和原理。
1. 网络协议栈:Linux内核中的网络协议栈负责处理网络通信的各个层次,包括物理层、数据链路层、网络层和传输层。
Socket通过网络协议栈与网络进行交互。
2. 套接字数据结构:在Linux内核中,套接字(Socket)被实现为一种数据结构,用于表示网络连接。
套接字数据结构包含了连接的相关信息,如IP地址、端口号等。
3. 文件描述符:在Linux中,套接字被视为一种文件,因此每个套接字都有一个对应的文件描述符。
通过文件描述符,进程可以对套接字进行读写操作。
4. 网络设备驱动程序:Linux内核中的网络设备驱动程序负责处理网络设备的底层操作,如发送和接收数据包。
套接字通过网络设备驱动程序与网络设备进行通信。
5. 网络协议处理:当进程通过套接字发送或接收数据时,Linux内核会根据套接字的协议类型(如TCP或UDP)进行相应的协议处理。
这包括建立连接、数据分片、错误检测等操作。
6. 系统调用:在用户空间中,进程通过系统调用(如socket、bind、connect等)来创建和操作套接字。
系统调用会触发内核中相应的函数,完成套接字的创建和操作。
总的来说,Linux内核中的Socket实现涉及到网络协议栈、套接字数据结构、文件描述符、网络设备驱动程序、网络协议处理和系统调用等多个组件和原理。
这些组件和原理共同工作,使得进程能够通过套接字进行网络通信。
{"code":0,"msg":"请求出现异常","data":{}}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
课程设计课程名称Linux下基于socket的文件传输程序设计学生学院信息工程学院专业班级学号学生姓名指导教师2013 年12月27日引言在互联网已经基本普及的情况下,人们越来越依赖于信息网络。
因为互联网的使用,我们可以大大的节省了我们的时间及成本。
所以文件、信息的传输已经是人们生活中不可缺少的东西。
而现在主流的应用软件都是基于WINDOWS平台上开发运行的。
Linux操作系统本身具有非常高的安全性,不易感染病毒(这是WINDOWS系统所不能比拟的),而且可移植性强,应用于大多数的服务器。
所以我们应该多开发出适合人们使用的应用软件,使得Linux更加好的为广大网民使用以保障自身的安全性。
本课设主要介绍在Linux下的文件传输原理及功能,虽然不能与主流传输软件的功能相比,但是却是占用的资源比它要少·1课设背景分析这次课程设计的要求是在以Linux为内核的操作系统下,实现多线程文件传输系统功能模块。
系统模块分为服务器和客户端两部分,客户端实现对文件的上传、下载和查看服务器默认路径下的文件列表;服务器可以对文件进行管理操作,包括创建、删除和重命名等。
多线程文件传输是一种一对多或者多对多的关系,一般是一个服务器对应着多个客户端。
客户端通过socket连接服务器,服务器要为客户端创建一个单独进程(线程)监听每个客户端的请求。
创建好连接之后文件就可以通过流的形式传输。
linux内核中为我们提供了两种不同形式的读写流,包括read()、write()和send()、recv()。
客户机对文件的查看指令也是通过流传递给服务器,服务器根据请求类型返回不同相应流。
根据socket原理和特点绘画出链接流程图,将客户机与服务器的相互通信划分为不同的模块,每个模块负责独立的功能项。
服务器输入指令管理目录下的文件,create filename是创建文件命令,rename oldname newname是删除文命令,delete filename 是删除文件命令,同时监听着客户端的请求;客户端向服务器发送上传、下载和查看请求,从而得到不同的相应,包括将文件下载到当前路径下,从当前路径下上传文件给服务器,列出服务器的文件列表。
·2网络通信原理及socket简介2.1网络通信原理(TCP)国际标准化组织(ISO)在1978年提出开放系统互连参考模型(OSI:open system interconnection reference mode),该模型是设计和描述网络通信的基本框架。
OSI采用分层的额结构化技术将通信网络分为7层,从低到高为物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
TCP/IP参考模型是由美国国防部创建,且发展至今最成功的通信协议模型,与OSI模型对应,它将网络功能分为4层,包括网络接口层、网络层、传输层和应用层,每一层都有对应的协议。
在传输层的主要协议是TCP协议和UDP协议。
socket连接就是基于TCP协议。
TCP是一种可靠地数据传输协议。
它为应用程序提供可靠的通信连接。
适合于一次传输大批数据的情况。
并适用于要求得到响应的应用程序并通过3次握手。
其数据包头格式为:2.2 socket 简介在Linux 中的网络编程是通过socket 接口来进行的。
socket 是一种特殊的I/O 接口,它也是一种文件描述符。
它是一种常用的进程之间通信机制,通过它不仅能实现本地机器上的进程之间的通信,而且通过网络能够在不同机器上的进程之间进行通信。
每一个socket 都用一个半相关描述{协议、本地地址、本地端口}来表示;一个完整的套接字则用一个相关描述{协议、本地地址、本地端口、远程地址、远程端口}来表示。
socket 也有一个类似于打开文件的函数调用,该函数返回一个整型的socket 描述符,随后的连接建立、数据传输等操作都是通过socket 来实现的。
socket 是一种套接口,它把网络地址和端口号信息放在一个结构体中,也就是套接字地址结构。
结构图如下:通用套接口地址数据结构定义在<sys/socket.h>头文件中,形式如下: struct sockaddr套接口与ip 、端口号的关系 套接口 168.222.222.222 9999222.222.222.222 9999Ip 地址端口号{uint8_t sa_len;sa_family_t sa_family;char sa_data[14];};IPv4套接口地址数据结构以socketaddr_in 命名,定义在<netinet/in.h>头文件中,形式如下:struct socketaddr_in{unit8_t sin_len;sa_family_t sin_family;in_port_t sin_port;struct in_addr sin_addr;unsigned char sin_zero[8];}下图是TCP 套接口通信工作流程图:通信工作的大致流程:1) 服务器先用socket()函数来建立一个套接口,用这个套接口完成通信的监听及数据的收发。
2)服务器用bind()函数来绑定一个端口号和ip地址,是套接口与指定的端口号和ip关联。
3)服务器调用linsten()函数,是服务器的端口和Ip处于监听状态,等待网络中某一个客户机的连接请求。
4)客户机用socket()函数建立一个套接口,设定远程ip和端口5)客户机调用connect()函数连接远程计算机指定的端口。
6)服务器调用accept()函数来接受远程计算机的连接请求,建立起与客户机之间的通信连接。
7)建立连接之后,客户机用write()函数(或send())想socket中写入数据。
也可以用read()函数(或recv()函数)赌气服务器发送来的数据。
8)服务器用read()函数(或recv()函数)来读取客户机发来的数据,也可以用write()函数(或send()函数)来发送数据。
9)完成通信以后,使用close()函数关闭socket连接。
·3详细设计过程·3.1服务器端创建监听与文件管理服务器负责的功能模块主要有两部分,一是对连接进来客户端所有线程的管理和服务器目录下的文件管理;二是创建线程来单独监听客户端的动作。
为了便于管理,我们创建两个user.txt和client.txt两个文档来分别负责服务器的连接和客户端的连接。
user.txt中存放了服务器名和密码。
client.txt存放了连接客户端名字和密码。
我们首先对服务器的创建有个监测,即在启动时先核实服务器的所有者username和密码password,将输入的用户、密码与user.txt中的用户密码比较,匹配成功则同意启动,否则return -1表失败。
接着创建一个socket套接口,绑定Ip设置客户端的最大连接数为10,然后创建一个sever线程来实现对服务器本身监听动作。
主体代码见最后接下来创建线程完成对客户端的监听监听等待连接:while(1){sockdata = accept(sockfd,(struct sockaddr*)0,(int*)0);…………….我们定义结构体:struct client_t{pthread_t tid;int conn_fd;int used;char name[20];}p_client[10];来存放每个客户端的socket信息、线程标识、使用号、连接号和客户名。
创建线程实现单独监听:p_client[i].conn_fd = sockdata;p_client[i].used = i;strcpy(p_client[i].name , client_name);pthread_create(&p_client[i].tid,NULL,&client_conn,&p_client[i])接下来是线程client_conn()的功能监听客户端的功能完成。
·3.2客户端连接与文件传输在客户端这边我们同样适用了检测机制,运行客户机时要将用户名、密码以及ip地址和端口号作为参数输进来,先建立与服务器的连接,然后将用户名和密码发送到服务端检测,如果检测失败则接收到一条拒绝信息,连接断开,如果检测成功则接收到一条确认信息,双方通信开始。
主体代码见最后:到此为止我们已经实现了服务器和客户端的主体功能,具体代码查看附录文件夹。
具体代码如下:服务端:#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<string.h>#include<sys/socket.h>#include<sys/stat.h>#include<arpa/inet.h>#include <sys/resource.h>#include <sys/types.h>#include <dirent.h>#define MAXBUF 256/*-------start of fileList functions----------*/ int fileSize(char fileName[]);//文件信息typedef struct fileinfo{char name[256];char fullName[1024];int size;time_t mod_time;char type[10];}fileinfo;//文件列表typedef struct filelist{fileinfo file;struct filelist* nextfile;}fileList;//function getfilelist//输入目录名//输出目录下的文件列表头指针fileList * getFileList(char name[1024]){fileList *head=NULL;fileList *cur=NULL;char name_temp[1024];//目录DIR * dir;//目录环境struct dirent *dir_env;//文件描述struct stat stat_file;//初始化headhead =(fileList*)malloc(sizeof(fileList)); head->nextfile = NULL;//打开目录dir=opendir(name);while(dir_env=readdir(dir))//读文件描述表{//排除.和..if(strcmp(dir_env->d_name,".")==0 || strcmp(dir_env->d_name,"..")==0)continue;//把文件全名保存到新变量strcpy(name_temp,name);strcat(name_temp,dir_env->d_name);stat(name_temp,&stat_file);//获取文件描述信息//将文件信息存放到链表中//产生临时节点cur=(fileList*)malloc(sizeof(fileList));//cur赋值//文件名,fullName=cur_dir+"name";strcpy(cur->,dir_env->d_name);strcpy(cur->file.fullName,name_temp);//文件大小//文件类型if( S_ISDIR(stat_file.st_mode)){cur->file.size = 0;strcpy(cur->file.type,"mulu");strcat(cur->file.fullName,"/");}else{cur->file.size = stat_file.st_size;strcpy(cur->file.type,"file");}//修改日期cur->file.mod_time = ctime(&stat_file.st_mtime);//将临时节点插入head中if(head->nextfile ==NULL){head->nextfile = cur;cur->nextfile = NULL;}else{cur->nextfile = head->nextfile;head->nextfile = cur;}}return head;}//showAllNode//输入:目录//输出:次目录下所有的文件,和所有目录之下的文件void showAllNode(fileList *head){fileList * temp;//数组索引int i=0,j=0;//如果head为空,直接返回fileList * headArray[1024];if(head == NULL)return ;//输出当前目录printf("%s ",head->file.fullName);printf("\n");//输出head中的文件temp =head->nextfile;char fileListString[MAXBUF];FILE *file;char _temp[30];strcpy(_temp,"temp.txt");file=fopen(_temp,"w");if(file==NULL){printf("The file is created failed!");exit(1);}while(temp){//判断是否为文件,是文件显示文件//若为目录,将目录名放入队列,求队列目录if (strcmp(temp->file.type,"file")==0){bzero(fileListString,MAXBUF);printf("file:%s ",temp->file.fullName);strcat(fileListString,temp->file.fullName);strcat(fileListString,"\n");while ((strlen(fileListString)) > 0){int write_length = fwrite(fileListString, sizeof(char), strlen(fileListString), file);if (write_length < strlen(fileListString)){printf("File Write into Failed\n");break;}bzero(fileListString, MAXBUF);}}else{if(i>=1024){printf("there are too many direcotry\n");return;}//头节点初始化headArray[i] = getFileList(temp->file.fullName);//头节点名称strcpy(headArray[i]->file.fullName,temp->file.fullName); i++;}temp=temp->nextfile;}fclose(file);//对目录队列中目录使用递归,直到结束for(j=0;j<i;j++)showAllNode(headArray[j]);return ;}//showList//输入:列表头//输出:显示列表,返回voidvoid showList(fileList * head){//判断head 是否为空,若为空直接返回if(head == NULL)return;//若不为空则显示它的内容while(head){printf("%s\n",head->file.fullName);head = head->nextfile;}return ;}/*----------end of fileList functions-----------*/void main(){int opt=1;while(opt!=0){printf("Please choose your choice bellow:\n");printf("1:Manage the files.\n");printf("2:Connect the clients.\n");char window[2];scanf("%s",window);if((strncmp(window,"1",1))==0){printf("Please input your choice bellow:\n");printf("1: Create a new file.\n");printf("2: Delete a file.\n");printf("3: Rename a known file.\n");char choice[2];scanf("%s",choice);if((strncmp(choice,"1",1))==0){printf("Please input the new file name:");char filename[20];scanf("%s",filename);FILE *file;file=fopen(filename,"w");if(file==NULL){printf("The file created failed!\n");}else{printf("The file has created successfully.\n");}continue;}else if((strncmp(choice,"2",1))==0){printf("Please input the file name with the file path you want to delete:\n");char filename[20];scanf("%s",filename);remove(filename);printf("The file has been deleted successfully.\n");continue;}else{printf("Please input the file name you want to rename:\n");char _old[20];scanf("%s",_old);printf("Please input the new file name:\n");char _new[20];scanf("%s",_new);int result = rename( _old, _new );if( result != 0 )printf( "Could not rename '%s'\n", _old );elseprintf( "File '%s' renamed to '%s'\n", _old, _new );continue;}}else{int ssock;int clen;struct sockaddr_in client_addr,server_addr;char buf[MAXBUF];if((ssock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))<0){ perror("socket error:");exit(1);}printf("Run the server successfully.\nAnd now waiting the client comming...\n");memset(&server_addr,0,sizeof(server_addr));server_addr.sin_family=AF_INET;server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");server_addr.sin_port=htons(6669);if(bind(ssock,(struct sockaddr *)&server_addr,sizeof(server_addr))<0){perror("bind error:");exit(1);}int window=1;while(window!=0){clen=sizeof(client_addr);recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr,&clen);printf("%s\n",buf);if((strncmp(buf, "0", 1)) == 0){if((strncmp(buf, "0yy", 7)) == 0){strcpy(buf,"yes");printf("It's username and right.\n");}else{strcpy(buf,"no");printf("It's username but wrong.\n");}sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr ,sizeof(client_addr));}else if((strncmp(buf, "1", 1)) == 0){if((strncmp(buf, "1123", 4)) == 0){strcpy(buf,"yes");sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr ,sizeof(client_addr));printf("It's password and right.\n");recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr,&clen);if((strncmp(buf, "upload", 5)) == 0){printf("The client is going to upload file...\n");recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr,&clen);//get filenameprintf("The filename of the file uploaded by user is:%s\n",buf);FILE *file;char temp[30];strcpy(temp,"recieve/");strcat(temp,buf);file=fopen(temp,"w");if(file==NULL){printf("The file is created failed!");exit(1);}bzero(buf, MAXBUF);recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr,&clen);while (strlen(buf) > 0){int write_length = fwrite(buf, sizeof(char), strlen(buf), file);if (write_length < strlen(buf)){printf("File Write into Failed\n");break;}bzero(buf, MAXBUF);}fclose(file);printf("Recieve file already success.\n");}else{printf("The client wants to download file.\n");printf("Send the filelist to the client...\n");//filelistfileList *mylist;//显示的目录char name[1024]="recieve/";//取得目录下文件//头指针传递的目录或者文件名mylist =getFileList(name);strcpy(mylist->file.fullName,name);//显示目录下文件//showList(mylist);//显示目录下所有文件showAllNode(mylist);//send fileListFILE *file;char temp[30];strcpy(temp,"temp.txt");file=fopen(temp,"r");if(file==NULL){printf("The file cannot open!");exit(1);}else{printf("\nThe fileListString open successfully!\n");bzero(buf,MAXBUF);int lengsize = 0;while((lengsize = fread(buf,1,MAXBUF,file)) > 0){printf("lengsize = %d\n",lengsize);sendto(ssock,(void*)buf,MAXBUF,0,(struct sockaddr*)&client_addr,sizeof(server_addr));printf("%s\n",buf);bzero(buf, MAXBUF);}printf("The fileListString has been sent to the client already.\n");}fclose(file);bzero(buf, MAXBUF);recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr,&clen);printf("The client choosen file: %s\n",buf);strcpy(temp,"recieve/");strcat(temp,buf);file=fopen(temp,"r");if(file==NULL){printf("The file is created failed!");exit(1);}else{printf("The file open successfully!\n");printf("The file is downloading to the client now...\n");bzero(buf,MAXBUF);int lengsize = 0;while((lengsize = fread(buf,1,MAXBUF,file)) > 0){printf("lengsize = %d\n",lengsize);sendto(ssock,(void*)buf,MAXBUF,0,(struct sockaddr*)&client_addr,sizeof(server_addr));bzero(buf, MAXBUF);}printf("The file has been downloaded already.\n");}fclose(file);exit(1);//还可以显示此时的文件目录信息,检查是否完成了上传}close(ssock);window=0;}else{strcpy(buf,"no");sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr ,sizeof(client_addr));printf("It's password but wrong.\n");}}}}}}客服端:#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<strings.h>#include<string.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<netdb.h>#define PORT 6669#define MAXBUF 256int check_passwd(int sockfd);int tra_file(int sockfd);void main ( int argc, char *argv[]){char username[20];char password[20];char temp[21];char window;printf("Please input your selections bellow:\n");printf("1:Login the server with your username and password\n");printf("2:Registe a newly user now.\n");printf("0:Exit the system.\n");window=getchar();while(window>0){if(window=='1'){int key=0;printf("Please input your username:");scanf("%s",username);printf("%s\n",username);int ssock;int clen;struct sockaddr_in client_addr,server_addr;char buf[MAXBUF];if((ssock = socket(AF_INET,SOCK_DGRAM,0))<0){perror("socket error:你暂时不能登录服务器server,请稍后再登录...\n");exit(1);}else{while(key==0){memset(&server_addr,0,sizeof(server_addr));server_addr.sin_family =AF_INET;server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");server_addr.sin_port=htons(PORT);strcpy(temp,"0");strcat(temp,username);strcpy(buf,temp);sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&server_addr,sizeof(server_addr));printf("你已经发送username(%s)给server请等待响应...\n",buf);clen=sizeof(client_addr);recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&server_addr,&clen);printf("你已经得到了server的响应:%s\n",buf);if((strncmp(buf, "yes", 3)) != 0){printf("The username you inputed is wrong!\n");window='1';close(ssock);printf("Please input your username:");scanf("%s",username);}else{close(ssock);key=1;}}}printf("Please input your password:");scanf("%s",password);printf("%s\n",password);if((ssock = socket(AF_INET,SOCK_DGRAM,0))<0){perror("socket error:你暂时不能登录服务器server,请稍后再登录...\n");exit(1);}else{key=0;while(key==0){memset(&server_addr,0,sizeof(server_addr));server_addr.sin_family =AF_INET;server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");server_addr.sin_port=htons(PORT);bzero(temp,21);strcpy(temp,"1");printf("%s\n",temp);strcat(temp,password);strcpy(buf,temp);sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&server_addr,sizeof(server_addr));printf("你已经发送password(%s)给server请等待响应...\n",buf);clen=sizeof(client_addr);recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&server_addr,&clen);printf("你已经得到了server的响应:%s\n",buf);if((strncmp(buf, "yes", 3)) != 0){printf("The password you inputed is wrong!\n");window='1';close(ssock);printf("Please input your password:");scanf("%s",password);}else{//file list display and file chooseprintf("Please choose eithor upload file or download file bellow:\n");printf("1:upload file.\n");printf("2:download file.\n");char choose[2];scanf("%s",choose);char path[20];char filename[20];if((strncmp(choose,"1",1))==0){printf("please input the path you want to upload end with '/':\n");scanf("%s",path);printf("Please input the file you want to upload:\n");strcpy(buf,"upload");sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&server_addr,sizeof(server_addr));scanf("%s",filename);strcat(path,filename);strcpy(buf,filename);sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&server_addr,sizeof(server_addr));FILE *file;file=fopen(path,"r");if(file==NULL){perror("The file open failed!");exit(1);}else{printf("The file open successfully!\n");printf("The file is uploading now...\n");bzero(buf,MAXBUF);int lengsize = 0;while((lengsize = fread(buf,1,MAXBUF,file)) > 0){printf("lengsize = %d\n",lengsize);sendto(ssock,(void*)buf,MAXBUF,0,(struct sockaddr*)&server_addr,sizeof(server_addr));bzero(buf, MAXBUF);}printf("The file has been uploaded already.\n");exit(1);//还可以显示此时的文件目录信息,检查是否完成了上传}}else{bzero(buf,MAXBUF);strcpy(buf,"download");sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&server_addr,sizeof(server_addr));printf("The filelist supported by server is bellow:\n");bzero(buf,MAXBUF);recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&server_addr,&clen);printf("%s\n",buf);printf("Please input the file you want to download :\n");scanf("%s",filename);strcpy(buf,filename);sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&server_addr,sizeof(server_addr));bzero(buf,MAXBUF);FILE *file;char temp[30];strcpy(temp,"download/");strcat(temp,filename);file=fopen(temp,"w");if(file==NULL){printf("The file is created failed!");exit(1);}bzero(buf, MAXBUF);recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&server_addr,&clen);while (strlen(buf) > 0){int write_length = fwrite(buf, sizeof(char), strlen(buf), file);printf("The write_length is:%d\n",write_length);if (write_length < strlen(buf)){printf("File Write into Failed\n");break;}bzero(buf, MAXBUF);}fclose(file);printf("Download file already success.\n");}close(ssock);key=1;window=0;}}}}else if(window=='2'){printf("Please input your newly username:");scanf("%s",username);printf("Please input your newly password:");scanf("%s",password);}else {break;}}}·4总结体会Linux是我首次接触的,所以对这次的课设还是感到有些无力。