분류 전체보기
- 사기꾼 인생 조지는 꿀팁들 2019.08.28
- POST 방식 파일전송 BASE64, GZipStream활용 2019.04.03
- 음... 2019.01.28
- asp.net asp:Image에 MemoryStream 이미지 데이터 넣기 2019.01.24
- asp.net 컨트롤 동적생성 2019.01.24
- 오래전 일이다. 2018.12.12
- 이쁜이들 2018.11.19
- 비트코인 2018.11.16
- HtmlInputFile의 첨부파일을 byte[]로변환 2018.11.16
- 가을 2018.10.08
사기꾼 인생 조지는 꿀팁들
POST 방식 파일전송 BASE64, GZipStream활용
복잡한 문제를 해결해야했다.
현상황은 다음과 같다.
두대의 iis가 있다. 한쪽은 WebServer이고 다른한쪽은 ImageServer이다.
골때리는 점은 Web에서 Img로 파일을 업로드할때 파일공유방식으로 전송하고 있다는 점이다.
Web이 \\ImgServerPath 와같이 공유폴더로 접근해서 파일을 업로드하고있다.
문제는 Web서버를 한대 증설하면서 공유폴더방식으로 접근이 안된다는 점이다. GUI단에서는 작업이 되지만
IIS수준에서는 붙지 않아서 파일업로드를 못하고 있다. 이를 해결하기 위해 잔머리를 굴렸다.
그러다가 파일을 Base64String으로 변환해서 POST전송하면 되겠다는 아이디어를 떠올렸다.
어차피 ImgServer도 IIS이므로 동일한 환경으로 세팅이 가능하기에 Img에도 asp.net을 구축할 수 있다.
구현단계에서 발견한 추가문제가 있었다.
5MB이상용량의 파일을 전송할 수가 없었다. 10M이상의 파일을 업로드 하지 못하기 때문에 이를 해결하기 위해 머리를 또 굴렸다.
Base64로 변환된 String은 길이기 길기때문에 잘릴 수도 있겠다 싶었다.
그래서 Base64를 압축해서 전송하면되겠다는 두번째 아이디어를 떠올렸다. 이문제를 며칠 동안 찾아 해맸다.
그리고 해결했다.
절차를 다시 정리하면 다음과 같다.
1. 파일을 MemoryStream으로 변환(MemoryStream생성과정에 GZipStream을 통해 압축)
2. MemoryStream을 Base64로 변환
3. Base64문자열을 POST로 전송
4. POST로 받은 문자열을 파일로 변환
※ using System.IO.Compression; //GZipStream을 사용하기 위한 선언
A)파일전송
HttpFileCollection addFile = HttpContext.Current.Request.Files;
string url = "http://ImgServer.url/Data_send.aspx";
string sFiles_Name = "";
string postParm = "";
string tmpParm = "";
for (int i = 0; i < addFile.Count; i++)
{
HttpPostedFile postedFile = addFile[i];
if (postedFile.ContentLength > 0)
{
sFiles_Name = postedFile.FileName;
Stream sm = postedFile.InputStream;
BinaryReader br = new BinaryReader(sm);
byte[] byt = br.ReadBytes((Int32)sm.Length);
sm.Dispose();
br.Close();
string base64 = "";
using(MemoryStream ms = new MemoryStream())
{
using (BufferedStream bs = new BufferedStream(new GZipStream(ms, CompressionMode.Compress), (64 * 1024)))
{
bs.Write(byt, 0, byt.Length);
}
base64 = Convert.ToBase64String(ms.ToArray());
}
tmpParm += base64 + '#'; //#은 파일구분자(여러개의 파일을 추가했을경우)
}
//POST 파라미터
postParm = string.Format("save_data={0}", tmpParm);
try
{
//POST전송
byte[] datatCategory = UTF8Encoding.UTF8.GetBytes(postParm);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
req.Method = "POST";
req.ContentLength = datatCategory.Length;
Stream requestStream = req.GetRequestStream();
requestStream.Write(datatCategory, 0, datatCategory.Length);
requestStream.Close();
HttpWebResponse httpWebResponse = (HttpWebResponse)req.GetResponse();
StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream(), Encoding.GetEncoding("UTF-8"));
string rtn = streamReader.ReadToEnd();
streamReader.Close();
httpWebResponse.Close();
}
catch (Exception ex)
{
//throw ex;
}
B)파일수신(string url = "http://ImgServer.url/Data_send.aspx";에 해당)
HttpFileCollection addFile = HttpContext.Current.Request.Files;
string save_data = "";
try
{
save_data = Request.Form["save_data"].Replace(" ", "+"); //Replace해줘야함 "+"문자가 " "으로 변환되서 넘어옴
}
catch (Exception ex)
{
save_data = "";
Response.Write(ex.Message);
return;
}
if (save_data != null && save_data != "")
{
string[] aryFiles = save_data.Split("#");
string svrPath = Server.MapPath(".").Replace("\\", "/");
for (int i = 0; i < aryFiles.Length - 1; i++)
{
byte[] bytData = Convert.FromBase64String(aryFiles[i]);
try
{
DirectoryInfo di = new DirectoryInfo(svrPath + "/folder");
if (!di.Exists)
{
di.Create();
}
using(MemoryStream ms = new MemoryStream(bytData))
{
using(MemoryStream dms = new MemoryStream())
{
using(BufferedStream bs = new BufferedStream(new GZipStream(ms, CompressionMode.Decompress),(64*1024)))
{
bs.CopyTo(dms);
}
using (FileStream fs = new FileStream(svrPath + "/folder/save_filename.file", FileMode.Create, System.IO.FileAccess.Write))
{
byte[] bt = dms.ToArray();
dms.Read(bt, 0, (int)dms.Length);
fs.Write(bt, 0, bt.Length);
fs.Flush();
}
}
}
}
catch(Exception ex)
{
Response.Write("false : " + ex.Message);
return;
}
}
Response.Write("true");
}
※ 참고 : http://toreaurstad.blogspot.com/2014/01/compressing-byte-array-in-c-with.html
음...
asp.net asp:Image에 MemoryStream 이미지 데이터 넣기
System.Web.UI.WebControls.Image obj = new System.Web.UI.WebControls.Image();
System.IO.MemoryStream ms = new System.IO.MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
obj.ImageUrl = "data:image/png;base64," + Convert.ToBase64String(ms.ToArray(), 0, ms.ToArray().Length);
기존에는
Response.BinaryWrite(ms.ToArray());
으로 이미지를 aspx로 뿌리는 방식을 썼었는데 한번에 하나의 파일밖에 뿌릴 수 없어서 방법을 찾아봤다.
출처 : https://www.codeproject.com/Questions/642132/asp-net-displaying-image-from-MemoryStream
asp.net 컨트롤 동적생성
aspx단에 Panel컨트롤 생성
<asp:Panel ID="pnl" runat="server"></asp:Panel>
System.Web.UI.WebControls.Image obj = new System.Web.UI.WebControls.Image();
System.IO.MemoryStream ms = new System.IO.MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
obj.ImageUrl = "data:image/png;base64," + Convert.ToBase64String(ms.ToArray(), 0, ms.ToArray().Length);
obj.ID = "img" + ii.ToString();
pnl.Controls.Add(objImg);
Panel에 Image컨트롤을 추가하는 방식
오래전 일이다.
IT개발자로 일하다 보면 황당한 요구를 하는 사람들을 가끔보게된다.
7,8년 전쯤 한 거래처가 그랬다.
당시나는 전자칠판 소프트웨어를 개발하고있었다.
개발하려고 하던것도 아니었고 거래처에서 요구를 하니 어찌어찌 하다 그리됐다.
A(기획), B(하드웨어), C(소프트웨어)를 담당하는 3사가 있었다. 내가 속해있던 업체는 C였고
B가 대형터치스크린 센서를 개발하고있었고 대기업쪽에 납품을 노리고 있던 상황이었다.
이를 본 A업체 사장이 오랬동안 사교육시장에 종사했던 경험으로
대형 터치스크린을 활용하여 전자칠판 사업을 하면 되겠다고 생각했다.
애석하게도 A,B,C는 어느정도 관계가 있는 회사였다.
A는 B와 C를 활용하면 괜찮은 사업이 가능하리라 생각했다.
A의 초기기획안은 내가봐도 그럴듯 했다. 초반엔 그럴듯했었다...
A가 처음에 C에 요구한 것은 하드웨어는 거의 완성됐으니 적용할만한 소프트웨어를 소개해달란 거다.
A가 제시한 금액이 너무 낮았기에 이에 응할 수 있는 업체가 거의 없었고
기획단계에서 A는 다양한 기능이 필요치 않은 번들수준의 S/W를 제공하여 박리다매로 팔겠다는 생각이었다.
해당금액에 응할 수 있는 업체가 없어서 그냥 내가있던 C에서 직접개발하기로 했다.
간단한 그림판을 대충 급조해서 만든 시제품을 가져갔더니 A의 표정이 좋지 않았다.
"수준 높고 검증된 소프트 웨어를 원한다."는게 그이유였다.
막 삽을 뜬 소프트웨어가 어찌그리 될수있겠냐만 A의 요구에 맞추기 위해 만들던 프로그램을 포기하고
프리랜서에게 웃돈을 얹어 주고 솔루션을 사왔다. 제법괜찮은 제품을 사왔고 A도 만족한 눈치였다.
문제는 그때부터 A의 눈높이가 너무 올라갔다는 거다.
이런저런 기능을 추가해달라고 계속요구하기 시작했다. 이를 다 쳐내지도 못했고
결정적으로 기술적으로 타당한지에 대한 검토가 전혀이뤄지지 않은 상태에서 무리하게 기획을 해갔다.
일정이나 비용의 문제가 아니라 순수하게 그런 기능이 구현가능한지에 대한 검토가 이뤄지지 않았다.
일방적으로 기획하고 일정을 잡아서 C에게 통보를 해댄다.
어디까지나 본인들이 甲이라 생각해서 그랬지 싶은데 곰곰히 생각하니 이게 뭐하는 짓인지 싶었다.
사업의 핵심솔루션을 직접개발하는 입장도 아닌 자들이 솔루션을 휘두르려하고있고 결정적으로 C가 개발하는 소프트웨어의
소유권마저 가져가고 싶어했다. (A에게 받기로 한돈보다 프리랜서에게 준돈이 더많았고 그마저도 다 받지 못한 상황이었다.)
그렇게 몇가지 기술적으로 무리한 요구들이 모이니 도저히 감당이 안 됐다.
기술적으로 무리한 요구 몇가지를 정리하면 다음과 같다.
1. 그당시만해도 WinXP에서 Win7으로 갈아타던 시절이라 시중에 XP사용자가 많았으므로 XP에서도 동일한 서비스가 제공되야 한다는 이유로
WinXP에 멀티터치를 지원하게 해달라고 한다.
=> 이건 거의 윈도우 API를 개발하는 수준이었다. 그때도 지금도 이런 개발을 할 능력이 나에게는 없다. 할생각도 없고
2. 당시 인지도있던 마인드맵 프리웨어의 기능이 마음에 든다고 우리가 개발중인 제품에 기능을 탑재하겠다고 요구한다. 기술적으로 불가능하다하니
DLL파일 몇개 복사하면 다되는거 아니냐고 하더라.
=>내가 A사장에게 한마디했다. "일이 그렇게 쉽게 되는 거면 나같은 사람은 필요가 없는 거다."
3. 전자칠판에 그림이나 글을 쓰다가 면적이 넓은 물건이 칠판에 올라가면 지우개모드로 동작하게 해달라고 요구를 했다.
=>하드웨어에서 이게 인식가능한지 아닌지도 모르겠고 결정적으로 저시점에 H/W 샘플을 받지 못해서 없어서 검토조차 못했다.
이쯤되니 A가 요구하는 것들이 무엇인지 명확해졌다. 손에 잡히지 않는 것을 잡을 수 있다고 생각했나보다.
A와 계속일을 하는 것이 단순히 스트레스의 문제가 아니라 굉장히 위험한 행동이라는 생각이 들었다
A의 문제는 H/W, S/W에 대한 일절의 기술적 이해가 없이 일방적으로 기획을 했다는 것이다.
그 중간에 숨어있던 비용적 시간적 윤리적 문제조차 차치하고 기본적으로 본인들이 작업하는 결과물의 가능여부를 이해하지 못했다.
기술적으로 전혀 검토되지 않은 기능을 제품 홍보물에 올렸고 소비자들에게 시연을 하기 위한 일정을 지속적으로 어겼다.
적어도 최초 기획했던 번들수준은 애초에 완성되있었음에도 불구하고 쓸데없이 경쟁제품들의 완성도에 집착하여
본제품의 출시조차 하지 못하고 사업을 말아먹었다.
게다가 처음 계획보다 시간이 무기한 늘어났다. 들어오는 비용도 없이 얼마돼지도 않은 초기비용으로 개발사(C)를 옭아매고있었고
A는 본인들이 甲인줄 알고 끝까지 휘두르려 했다. 내입장에서 얼토당토않은 기획안은 쳐내야 했지만 C의 사장은 왠만해서는 수용하려는 태도였고
시간적으로 비용적으로 그리고 실현가능성 면에서 엉망인 상태였으므로 위험하기 그지없는 상태를 회피하기 위해 나는 C를 퇴사했다.
퇴사한 이후에 시간이 흘러 C도 A와 사업을 정리했고 A는 다른 프리랜서 개발자를 섭외해서 개발을 지속했다고 한다.
몇년을 전자칠판 사업에 매달려있었는데 그후 종종 들리는 이야기를 들어보니 여전히 기술적인 이해 자체를 하지 않고있었다.
당연하게도 그회사는 망했다.
얼토당토 않은 요구사항을 늘어놓던 A사장에게 내가 해줬던 이야기가 있다.
A : "이런저런 (무리한) 기능 구현을 왜 못하냐?"
나 : "그런거 할줄 알면 내가 여기 왜있냐"
이쁜이들
비트코인
몇년전부터 나는 고민에 빠져있었다.
심각한 고민은 아녔지만 아마 삼사년쯤전부터 고민했던 것 같다.
그러다가 제작년부터 본격적으로 고민했다.
비트코인을 해야하나???
그당시에는 돈이될 것이 확실해보였다.
수중에 있던 몇백만원을 털어서 한번사볼까 말까 계속간만봤다.
그런데...
한가지 마음한편에 걸리는게 있었다.
비트코인 투자(?)라는 행위의 본질적인 이해가 되지를 않았던 것이다.
과연 이것을 투자라고 할수있을지...
그 투자라는 것을 하는것이 과연 건전한 것인지...
제작년 가을부터 작년 초순까지 몇개월을 다시 고민했다.
고민하고 고민할 수록 나로서는 비트코인에 참여하기 어렵겠다는 확신만 들었다.
심지어 돈이 될것이라는 확신이 있는 상태에서도 말이다.
내가보기에 가상화폐는 도박이고 또 다단계와 같았다.
하루하루 등락에 일희일비하는 것이야 주식과도 비슷할 수 있다고 할수있으나
현물도없고 제공되는 서비스도 없는 철저한 무형의 투기를 위한 투기로서의 목적밖에 없는
그것에 도저히 발을 들여놓을 자신이 없었다.
무엇보다도 마음에 들지 않았던 점은 선행투자자들이 후행투자자들의 돈을 뽑아먹는 구조라고 밖에 보이지 않았다는 점이다.
다시말해 내가 돈을 벌면 누군가는 반드시 돈을 잃을 수밖에 없는 구조였다.
마치 다단계와 같이 후발주자들이 투자를 계속해야만 수익을 낼수있는 구조였으니 후발주자들이 더이상 유입되지 않는다면
존속할 수 없는 수익구조였다. 이런점을 다단계와 유사한 구조처럼 생각하였고
나로서는 가상화폐에 투자를 해서 수익을 기대한다는 행위자체가 돈을 벌기위해 수단을 가리지 않는 '부도덕한 행위'로
받아들여졌다.
그리고 공교롭게도 그 결단을 낸지 몇달도 되지않아 정부의 개입이 있었고 가상화폐의 가치는 수직하락했다.
어차피 언젠가 정부가 개입하리라는 짐작은 하고있었지만 정권이 바뀐덕인지 내가생각했던 것보다 꽤나 빠르게
개입했다. 나는 이조치가 꽤나 만족스럽지는 않았지만 다행이었다고 생각한다.
언젠가 점심을 먹으려고 칼국수집에 갔더니 내뒷자리에 있던 5,60대 손님두분이 비트코인 얘기를 하고있더라...
가정주부가 주식을 논하는 순간 이미 그바닥은 게임끝난거라는 낭설이 생각났다.
중,장년의 어른들이 가상화폐를 언급하는 것을 직접들었던 그순간 가상화폐의 끝이 보였다.
HtmlInputFile의 첨부파일을 byte[]로변환
byte[] data = null;
using (var br = new BinaryReader(uploadfile.PostedFile.InputStream))
{
data = br.ReadBytes(uploadfile.PostedFile.ContentLength);
}
#####################################################
byte[] data를 MemoryStream등으로 변환해서 쓸 수 있다ㅏ.
가을
늘 오늘처럼