안녕하세요. 명월입니다.
이 글은 C#의 콘솔 코드로 Java의 Servlet에 접속하는 방법(Post 데이터 값 전송과 파일 전송)에 대한 글입니다.
이전의 Java Servlet에서 C#의 RestAPI를 통해 접속하는 방법의 글에서 어떤 분이 Java Servlet에서 C# 콘솔로 접속하는 방법은 알겠는데 C# 콘솔에서 Java Servlet으로 접속하는 방법에 대해 물어보셔서 그것에 대한 답글입니다.
링크 - [C#] Java servlet에서 C#의 RestAPI를 통해 통신하는 방법
위 글에서는 사실 C#은 서버를 만들지 않는 이상 Java Servlet에서 C# 콘솔로 접속하는 게 어렵습니다. 왜냐면 콘솔 프로그램이 켜져 있는 것이 아니기 때문에...
그래서 제목은 Java Servlet에서 C#의 RestAPI를 통해 접속하는 방법이라고 한 것이지만, 사실 C# 콘솔 코드로 웹서버를 만드는 방법이 맞는 것이겠네요...
즉, 반대의 경우는 Java Servlet이 웹 서버 프로그래밍이기 때문에 접속하는 게 어렵지 않습니다.
그것에 관한 글을 찾아보니깐 이미 작성을 했더군요..
링크 - [C#] HttpConnection을 이용해서 웹 페이지 가져오기
링크 - [C#] 웹 서버로 HttpWebRequest를 이용하여 파일 업로드하는 방법
근데 위 글은 Java가 아닌 PHP로 예를 들었기 때문에.. 제가 Java로 다시 설명하겠습니다.
먼저 eclipse로 Java sevlet 프로젝트를 열고 index.jsp파일과 Test 서블릿 클래스 파일을 만들겠습니다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<!-- 해더 설정 -->
<head><title>Servlet Test</title></head>
<body>
<!-- form 태그 submit 버튼을 누르면 Test servlet으로 POST형식을 요청한다. -->
<form method="POST" action="Test?GetStringParam=helloworld">
<!-- 파라미터는 PostParam의 이름으로 nowonbun의 값을 전송한다. -->
<input type="text" name="PostParam" value="nowonbun">
<!-- Submit 버튼 -->
<input type="submit">
</form>
</body>
</html>
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// Test 서블릿
@WebServlet("/Test")
public class Test extends HttpServlet {
private static final long serialVersionUID = 1L;
// 생성자
public Test() {
super();
}
// Method GET으로 요청이오면 호출되는 함수
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// HTTP 결과 값을 "Served at 호스트 페이지, 메소드 형식"으로 출력한다.
response.getWriter().append("Served at : ").append(request.getContextPath()).append(" Method : GET");
// 콘솔 출력
System.out.println(request.getParameter("GetStringParam"));
}
// Method POST으로 요청이오면 호출되는 함수
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// HTTP 결과 값을 "Served at 호스트 페이지, 메소드 형식"으로 출력한다.
response.getWriter().append("Served at : ").append(request.getContextPath()).append(" Method : POST");
// 콘솔 출력
System.out.println(request.getParameter("PostParam"));
}
}
그리고 브라우저로 접속합니다.
그리고 브라우저 URL에 직접 /Test?GetStringParam=helloworld도 접속해 봅니다.
그리고 eclipse에서 GetString Parameter의 값이 제대로 콘솔에 출력이 되는지도 확인합니다.
Servlet 환경을 만들었습니다. 이제 C#에서 POST형식으로 접속을 해봅시다.
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Net.Http;
namespace Example
{
class Program
{
// HttpRequest를 실행하는 함수
public static string GetRequest(String url, HttpMethod method, object param = null)
{
// 파라미터가 있을 경우, 익명 클래스로 만들기 때문에 Reflection을 이용해서 데이터를 가져온다.
if (param != null)
{
// 버퍼
StringBuilder parameter = new StringBuilder();
// 파라미터키=파라미터값&파라미터키=파라미터값&파라미터키=파라미터값 의 형태로 만든다.
foreach (var p in param.GetType().GetProperties())
{
// 파라미터가 있으면 &표시로..
if (parameter.Length > 0)
{
parameter.Append("&");
}
// 파라미터 추가한다.
parameter.AppendFormat("{0}={1}", p.Name, p.GetValue(param));
}
// 버퍼를 String 형식으로 변환
param = parameter.ToString();
}
else
{
param = "";
}
// Http method가 GET 방식의 경우 파라미터를 url 주소 뒤에 붙인다.
if (HttpMethod.Get.Equals(method))
{
// URL에 이미 파라미터가 있으면
if (url.Contains("?"))
{
// 기존 파라미터로 연결한다.
url += "&" + param;
}
else
{
// 파라미터를 생성한다.
url += "?" + param;
}
}
// url를 통해 HttpWebRequest 클래스를 생성한다.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
// 해더의 메소드를 정의한다.
request.Method = method.ToString();
// 해더의 ContentType를 정의한다.
request.ContentType = "application/x-www-form-urlencoded";
// request에 프로퍼티로 정의되지 않는 해더의 경우는 Indexer의 형식으로 정의할 수 있다.
// 프로퍼티로 정의된 해더의 경우, 아래와 같이 정의할 경우 에러가 발생한다.
request.Headers["Upgrade-Insecure-Requests"] = "1";
// Http method가 POST 방식의 경우, 해더 아래에
if (HttpMethod.Post.Equals(method))
{
// 파라미터를 바이너리로 변환
byte[] byteArray = Encoding.UTF8.GetBytes((string)param);
// 바이너리 길이 설정
request.ContentLength = byteArray.Length;
// 스트림을 가져온다.
using (Stream dataStream = request.GetRequestStream())
{
// 스트림에 바이너리를 쓴다.
dataStream.Write(byteArray, 0, byteArray.Length);
}
}
// Http 프로토콜을 접속해서 response 받기
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
// 프로토콜의 반환 코드를 받을 수 있다. (200이면 정상이다.)
Console.WriteLine((int)response.StatusCode);
// 스트림으로 반환 결과값을 받는다.
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
// 스트림을 String형식으로 읽어온다.
return reader.ReadToEnd();
}
}
}
//실행 함수
static void Main(string[] args)
{
// 서블릿에 접속한다. POST 형식으로 PostParam의 값은 test
String html = GetRequest("http://localhost:8080/WebExample/Test", HttpMethod.Post, new { PostParam = "test" });
// 결과를 콘솔에 출력
Console.WriteLine(html);
// 아무키 누르면 종료
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
실행을 하게 되면 서블릿으로 부터 받는 Response 값을 받게 됩니다.
eclipse를 확인해서 C#에서 보낸 Post 데이터가 제대로 전송되어 콘솔에 표시되는지 확인해 봅니다.
C# 콘솔 프로그램에서 보낸 데이터가 콘솔에 표시되었습니다.
여기까지 단순히 서블릿에 접속하여 데이터를 보내는 것만으로는 내용이 부족하니 이번에는 Servlet에 파일 업로드 소스를 만들고 C# 콘솔로 파일 업로드하는 것까지 만들겠습니다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<!-- 해더 설정 -->
<head><title>Servlet Test</title></head>
<body>
<!-- 웹 폼 -->
<form method="POST" action="Test" enctype="multipart/form-data">
<!-- 파일 업로드 오브젝트 -->
<input type="file" name="PostParam" value="nowonbun">
<!-- Submit 버튼 -->
<input type="submit">
</form>
</body>
</html>
여기서 파일을 첨부하고 Submit 버튼을 누르면 파일 업로드가 되는 서블릿을 만들겠습니다.
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
// enctype="multipart/form-data"의 대응
@MultipartConfig
// 서블릿 설정
@WebServlet("/Test")
public class Test extends HttpServlet {
private static final long serialVersionUID = 1L;
// 생성자
public Test() {
super();
}
// 파일업로드는 post형식으로 바운더리로 요청이 오기 때문에 doGet은 필요가 없겠네요.
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 해더의 바운더리 영역을 취득한다.
Collection<Part> parts = request.getParts();
// 해더 영역을 전부 for문으로 탐색한다.
for (Part part : parts) {
// 파일 관계된 바운더리 데이터가 아니면 패스
if (!part.getHeader("Content-Disposition").contains("filename=")) {
continue;
}
// 해더 바운더리 영역에서 파일 이름을 추출한다.
String fileName = extractFileName(part.getHeader("Content-Disposition"));
// 파일 이름이 null이 아니거나 사이즈가 0보다 크면..
if (fileName != null && part.getSize() > 0) {
// 저는 임의의 d:\\work 폴더에 업로드 하겠습니다.
part.write("d:\\work\\" + File.separator + fileName);
part.delete();
}
}
}
// 헤더에서 파일 이름을 추출하는 함수
private String extractFileName(String partHeader) {
// 바운더리의 해더는 ;의 구분으로 데이터가 있다.
for (String cd : partHeader.split(";")) {
// 헤더 이름이 filename으로 시작하는 것이라면
if (cd.trim().startsWith("filename")) {
// '='부터 끝까지 따옴표는 제거
String fileName = cd.substring(cd.indexOf("=") + 1).trim().replace("\"", "");
// 그리고 디렉토리 표시 된것도 제거
int index = fileName.lastIndexOf(File.separator);
// 파일 이름 추출
return fileName.substring(index + 1);
}
}
// 위 조건에 맞지 않으면 null 리턴
return null;
}
}
여기까지 이전에 Servlet에서 파일 업로드하는 방법을 참고했습니다.
링크 - [Java] Servlet 환경 - 파일 업로드(프로그래스바로 파일 업로드 상태를 표시하는 방법)
이제 C# 콘솔에서 파일을 업로드합니다.
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
namespace Example
{
class Program
{
// 파일을 바이너리 형식(byte[])으로 변환
static byte[] ReadFileToBoundary(string filepath, string boundary)
{
// 바운더리 구분을 바이너리로 변환
var boundarybytes = Encoding.ASCII.GetBytes($"\r\n--{boundary}\r\n");
// 파일 정보 취득하기
FileInfo fileInfo = new FileInfo(filepath);
// 바운더리 해더 설정
var header = Encoding.ASCII.GetBytes($"Content-Disposition: form-data; name=\"{fileInfo.Name}\"; filename=\"{fileInfo.Name}\"\r\nContent-Type: application/octet-stream\r\n\r\n");
// 스트림으로 읽어오기
using (Stream stream = new MemoryStream())
{
// 바운더리 구분
stream.Write(boundarybytes, 0, boundarybytes.Length);
// 해더 설정
stream.Write(header, 0, header.Length);
// 파일 바이너리 설정
using (Stream fileStream = fileInfo.OpenRead())
{
fileStream.CopyTo(stream);
}
// 반환할 byte[] 설정
var ret = new byte[stream.Length];
// Stream seek를 맨앞으로.
stream.Seek(0, SeekOrigin.Begin);
// byte로 변환
stream.Read(ret, 0, ret.Length);
// 리턴
return ret;
}
}
// 실행 함수
static void Main(string[] args)
{
// 바운더리 마크 설정
string boundary = "**boundaryline**";
// 서블릿에 접속
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:8080/WebExample/Test");
// 해더 설정 (파일 전송)
request.ContentType = "multipart/form-data; boundary=" + boundary;
// 매서드 타입 설정
request.Method = HttpMethod.Post.ToString();
// request에 프로퍼티로 정의되지 않는 해더의 경우는 Indexer의 형식으로 정의할 수 있다.
// 프로퍼티로 정의된 해더의 경우, 아래와 같이 정의할 경우 에러가 발생한다.
request.Headers["Upgrade-Insecure-Requests"] = "1";
// KeepAvlie 설정
request.KeepAlive = true;
// 파일 읽어와서 바운더리 설정
var filelist = new List<byte[]>
{
ReadFileToBoundary(@"d:\\nowonbuntistory.png", boundary),
ReadFileToBoundary(@"d:\\nowonbun.png", boundary),
};
// 바운더리를 ascii코드로 변환
var endboundary = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--");
// Header를 제외한 총 크기
request.ContentLength = filelist.Sum(x => x.Length) + endboundary.Length;
// 서버로 전송할 Stream 취득하기
using (Stream stream = request.GetRequestStream())
{
// 바운더리 설정된 파일을 전송
foreach (var file in filelist)
{
stream.Write(file, 0, file.Length);
}
// 바운더리 구분 설정
stream.Write(endboundary, 0, endboundary.Length);
}
// 서버에 접속해서 Response 취득하기
using (var response = request.GetResponse())
{
// 서버로 부터 받는 Stream 취득하기
using (Stream stream2 = response.GetResponseStream())
{
// 스트림 Reader로 변환
using (StreamReader reader2 = new StreamReader(stream2))
{
// 콘솔에 표시
Console.WriteLine(reader2.ReadToEnd());
}
}
}
// 아무키가 누르세요...
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
저는 이미지 두개를 서버로 전송하겠습니다.
제대로 전송이 되었습니다.
여기까지 이전에 C# 콘솔에서 Web 페이지로 파일 업로드하는 방법을 참고했습니다.
링크 - [C#] 웹 서버로 HttpWebRequest를 이용하여 파일 업로드하는 방법
예전에는 PHP로 예제를 만들었는데 요번에는 Java Servlet을 대상으로 작성했습니다.
jsp의 경우는 웹 서버이기 때문에 소켓 프로그램밍 조금 안다면 접속 프로그램을 만드는 건 그렇게 어렵지 않습니다.
그리고 이 Tomcat이라는 어플리케이션 서버(WAS)는 예전보다 많은 부분의 성능이 좋아져서 웹 서버 프로그램 뿐만 스레드를 이용해서 여러가지 서버 프로그램으로도 사용이 가능합니다.(게임 서버도 작성 가능합니다.)
즉, 따로 멀티 스레드 서버 프로그램을 작성할 필요없이 그냥 Tomcat에다가 ServerSocket 인스턴스를 생성해서 소켓 서버로도 사용이 가능합니다.
링크 - [Java] Tomcat 서버에서 소켓 서버를 만드는 방법
링크 - [Java] Tomcat의 websocket을 이용해서 socket서버 만들기
여기까지 C#의 콘솔 코드로 Java의 Servlet에 접속하는 방법(Post 데이터 값 전송과 파일 전송)에 대한 글이었습니다.
궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.
'Development note > C#' 카테고리의 다른 글
[C#] 무료 게임 라이브러리 Monogame를 이용해서 퍼즐 게임 만들기 (0) | 2021.03.10 |
---|---|
[C#] Excel 파일을 PDF 및 이미지로 변환하는 방법 (Spire.Xls) (0) | 2021.03.09 |
[C#] 모바일 프로그램(Android, IOS)을 개발하는 방법(Xamarin, Cross-platform) (1) | 2021.03.03 |
[C#] 무료 게임 개발 라이브러리(Monogame, 구: XNA)을 설치하는 방법을 설치하는 방법 (0) | 2021.03.02 |
[C#] 퍼즐 게임 만들기 (0) | 2021.02.10 |
[C#] 프로그래밍에 필요한 pixel 이미지 만들기 그리고 스트라이프 이미지 만들기 (1) | 2021.01.29 |
[C#] 소리 파일(wav) 및 음악 파일(mp3)를 다루는 방법 (2) | 2021.01.27 |
[C#] Clipboard(복사 + 붙여넣기 기능)을 다루는 방법 (0) | 2021.01.26 |