//Send()메소드는 스트림을 통해 메시지를 내보냅니다. public static void Send(Stream writer, Message msg) { writer.Write(msg.GetBytes(), 0, msg.GetSize()); }
static void Main(string[] args) { if (args.Length < 1) { Console.WriteLine("사용법 : {0} <Directory>", Process.GetCurrentProcess().ProcessName); return; } uint msgId = 0; string dir = args[0]; if (Directory.Exists(dir) == false) Directory.CreateDirectory(dir); //서버 포트 const int bindPort = 5425; TcpListener server = null; try { //IP 주소를 0으로 입력하면 127.0.0.1뿐 아니라 OS에 할당되어 있는 어떤 주소로도 서버에 접속이 가능합니다. IPEndPoint localAddress = new IPEndPoint(0, bindPort); server = new TcpListener(localAddress); server.Start(); Console.WriteLine("파일 업로드 서버 시작... "); while (true) { TcpClient client = server.AcceptTcpClient(); Console.WriteLine("클라이언트 접속 : {0} ", ((IPEndPoint)client.Client.RemoteEndPoint).ToString()); NetworkStream stream = client.GetStream(); //클라이언트가 보내온 파일 전송 요청 메시지를 수신합니다. Message reqMsg = MessageUtil.Receive(stream); if (reqMsg.Header.MSGTYPE != CONSTANTS.REQ_FILE_SEND) { stream.Close(); client.Close(); continue; } BodyRequest reqBody = (BodyRequest)reqMsg.Body; Console.WriteLine( "파일 업로드 요청이 왔습니다. 수락하시겠습니까? yes/no"); string answer = Console.ReadLine(); Message rspMsg = new Message(); rspMsg.Body = new BodyResponse() { MSGID = reqMsg.Header.MSGID, RESPONSE = CONSTANTS.ACCEPTED }; rspMsg.Header = new Header() { MSGID = msgId++, MSGTYPE = CONSTANTS.REP_FILE_SEND, BODYLEN = (uint)rspMsg.Body.GetSize(), FRAGMENTED = CONSTANTS.NOT_FRAGMENTED, LASTMSG = CONSTANTS.LASTMSG, SEQ = 0 }; if (answer != "yes") { //사용자가 "yes"가아닌 답을 입력하면 클라이언트에게 "거부"응답을 보냅니다. rspMsg.Body = new BodyResponse() { MSGID = reqMsg.Header.MSGID, RESPONSE = CONSTANTS.DENIED }; MessageUtil.Send(stream, rspMsg); stream.Close(); client.Close(); continue; } else //yes 응답시 클라이언트에게 "승낙" 응답을 보냅니다. MessageUtil.Send(stream, rspMsg); Console.WriteLine("파일 전송을 시작합니다..."); long fileSize = reqBody.FILESIZE; string fileName = Encoding.Default.GetString(reqBody.FILENAME); //업로드 파일 스트림을 생성합니다. FileStream file = new FileStream(dir + "\\" + fileName, FileMode.Create); uint? dataMsgId = null; ushort prevSeq = 0; while ((reqMsg = MessageUtil.Receive(stream)) != null) { Console.Write("#"); if (reqMsg.Header.MSGTYPE != CONSTANTS.FILE_SEND_DATA) break; if (dataMsgId == null) dataMsgId = reqMsg.Header.MSGID; else { if (dataMsgId != reqMsg.Header.MSGID) break; } //메시지 순서가 어긋나면 전송을 중단합니다. if (prevSeq++ != reqMsg.Header.SEQ) { Console.WriteLine("{0}, {1}", prevSeq, reqMsg.Header.SEQ); break; } //전송 받은 스트림을 서버에서 생성한 파일에 기록합니다. file.Write(reqMsg.Body.GetBytes(), 0, reqMsg.Body.GetSize()); //분할 메시지가 아니라면 반복을 한 번만 하고 빠져 나옵니다. //if (reqMsg.Header.FRAGMENTED == CONSTANTS.NOT_FRAGMENTED) // break; //마지막 메시지이면 반복문을 빠져나옵니다. if (reqMsg.Header.LASTMSG == CONSTANTS.LASTMSG) break; } long recvFileSize = file.Length; file.Close(); Console.WriteLine(); Console.WriteLine("수신 파일 크기 : {0} bytes", recvFileSize); Message rstMsg = new Message(); rstMsg.Body = new BodyResult() { MSGID = reqMsg.Header.MSGID, RESULT = CONSTANTS.SUCCESS }; rstMsg.Header = new Header() { MSGID = msgId++, MSGTYPE = CONSTANTS.FILE_SEND_RES, BODYLEN = (uint)rstMsg.Body.GetSize(), FRAGMENTED = CONSTANTS.NOT_FRAGMENTED, LASTMSG = CONSTANTS.LASTMSG, SEQ = 0 }; //파일 전송 요청에 담겨온 파일 크기와 실제로 받은 파일의 크기를 비교하여 같으면 성공 메시지를 보냅니다. if (fileSize == recvFileSize) MessageUtil.Send(stream, rstMsg); else { rstMsg.Body = new BodyResult() { MSGID = reqMsg.Header.MSGID, RESULT = CONSTANTS.FAIL }; //파일 크기에 이상이 있드면 실패 메시지를 보냅니다. MessageUtil.Send(stream, rstMsg); } Console.WriteLine("파일 전송을 마쳤습니다."); stream.Close(); client.Close(); } } catch (SocketException e) { Console.WriteLine(e); } finally { server.Stop(); } Console.WriteLine("서버를 종료합니다."); }
static void Main(string[] args) { if (args.Length < 2) { Console.WriteLine( "사용법 : {0} <Server IP> <File Path>", Process.GetCurrentProcess().ProcessName); return; } string serverIp = args[0]; const int serverPort = 5425; string filepath = args[1]; try { //클라이언트는 OS에서 할당한 IP주소와 포트에 바인딩합니다. IPEndPoint clientAddress = new IPEndPoint(0, 0); IPEndPoint serverAddress = new IPEndPoint(IPAddress.Parse(serverIp), serverPort); Console.WriteLine("클라이언트: {0}, 서버:{1}", clientAddress.ToString(), serverAddress.ToString()); uint msgId = 0; Message reqMsg = new Message(); reqMsg.Body = new BodyRequest() { FILESIZE = new FileInfo(filepath).Length, FILENAME = System.Text.Encoding.Default.GetBytes(filepath) }; reqMsg.Header = new Header() { MSGID = msgId++, MSGTYPE = CONSTANTS.REQ_FILE_SEND, BODYLEN = (uint)reqMsg.Body.GetSize(), FRAGMENTED = CONSTANTS.NOT_FRAGMENTED, LASTMSG = CONSTANTS.LASTMSG, SEQ = 0 }; TcpClient client = new TcpClient(clientAddress); client.Connect(serverAddress); NetworkStream stream = client.GetStream(); //클라이언트는 서버에 접속하자마자 파일 전송 요청 메시지를 보냅니다. MessageUtil.Send(stream, reqMsg); //그리고 서버의 응답을 받습니다. Message rspMsg = MessageUtil.Receive(stream); if (rspMsg.Header.MSGTYPE != CONSTANTS.REP_FILE_SEND) { Console.WriteLine("정상적인 서버 응답이 아닙니다.{0}", rspMsg.Header.MSGTYPE); return; } //서버에서 전송 요청을 수락했다면 파일 스트림을 열어 서버로 보낼 준비를 합니다. if (((BodyResponse)rspMsg.Body).RESPONSE == CONSTANTS.DENIED) { Console.WriteLine("서버에서 파일 전송을 거부했습니다."); return; } using (Stream fileStream = new FileStream(filepath, FileMode.Open)) { byte[] rbytes = new byte[CHUNK_SIZE]; long readValue = BitConverter.ToInt64(rbytes, 0); int totalRead = 0; ushort msgSeq = 0; byte fragmented = (fileStream.Length < CHUNK_SIZE) ? CONSTANTS.NOT_FRAGMENTED : CONSTANTS.FRAGMENTED; while (totalRead < fileStream.Length) { int read = fileStream.Read(rbytes, 0, CHUNK_SIZE); totalRead += read; Message fileMsg = new Message(); byte[] sendBytes = new byte[read]; Array.Copy(rbytes, 0, sendBytes, 0, read); fileMsg.Body = new BodyData(sendBytes); fileMsg.Header = new Header() { MSGID = msgId, MSGTYPE = CONSTANTS.FILE_SEND_DATA, BODYLEN = (uint)fileMsg.Body.GetSize(), FRAGMENTED = fragmented, LASTMSG = (totalRead < fileStream.Length) ? CONSTANTS.NOT_LASTMSG : CONSTANTS.LASTMSG, SEQ = msgSeq++ }; Console.Write("*"); //모든 파일의 내용이 전송될 때까지 파일 스트림을 0x03메시지에 담아 서버로 보냅니다. MessageUtil.Send(stream, fileMsg); } Console.WriteLine(); //서버에서 파일을 제대로 받았는지에 대한 응답을 받습니다. Message rstMsg = MessageUtil.Receive(stream); BodyResult result = ((BodyResult)rstMsg.Body); Console.WriteLine("파일 전송 성공 : {0}", result.RESULT == CONSTANTS.SUCCESS); } stream.Close(); client.Close(); } catch (SocketException e) { Console.WriteLine(e); } Console.WriteLine("클라이언트를 종료합니다."); }