[{"data":1,"prerenderedAt":1546},["ShallowReactive",2],{"post-document:\u002Fbackend\u002Fnetwork\u002F2026\u002F08\u002F12\u002FSocket\u002F":3},{"id":4,"title":5,"body":6,"categories":1532,"date":1535,"description":16,"extension":1536,"image":1537,"key_concepts":1537,"last_modified_at":1537,"legacyPath":1538,"meta":1539,"navigation":428,"part":1537,"path":1541,"published":428,"robots":1537,"seo":1542,"series":1537,"stem":1543,"strengths":1537,"summary":1537,"tags":1544,"tradeoffs":1537,"__hash__":1545},"posts\u002Fposts\u002FBackend\u002FNetwork(중요)\u002FSocket.md","Socket이란 무엇인가",{"type":7,"value":8,"toc":1519},"minimark",[9,13,17,20,26,31,269,273,276,286,296,349,353,359,370,384,490,494,501,507,583,588,594,647,652,658,701,705,708,715,964,971,1117,1121,1124,1189,1193,1196,1216,1219,1231,1234,1246,1250,1253,1259,1262,1268,1272,1335,1339,1473,1476,1515],[10,11,5],"h2",{"id":12},"socket이란-무엇인가",[14,15,16],"p",{},"소켓(Socket)은 프로그램이 네트워크를 통해 다른 프로그램과 데이터를 주고받을 수 있게 해주는 통신 창구입니다.",[14,18,19],{},"쉽게 말하면 다음과 같습니다.",[21,22,23],"blockquote",{},[14,24,25],{},"IP 주소가 건물의 주소라면, 포트 번호는 건물 안의 특정 방 번호이고, 소켓은 그 방에서 실제로 대화하기 위한 연결 통로입니다.",[27,28,30],"h3",{"id":29},"공부에-필요한-핵심-용어","공부에 필요한 핵심 용어",[32,33,34,50],"table",{},[35,36,37],"thead",{},[38,39,40,44,47],"tr",{},[41,42,43],"th",{},"용어",[41,45,46],{},"정의",[41,48,49],{},"쉬운 예시",[51,52,53,65,76,87,98,116,129,143,154,165,176,187,198,209,220,234,245,258],"tbody",{},[38,54,55,59,62],{},[56,57,58],"td",{},"네트워크",[56,60,61],{},"여러 컴퓨터가 데이터를 주고받는 연결 환경",[56,63,64],{},"내 컴퓨터에서 다른 컴퓨터의 웹 사이트에 접속하는 것",[38,66,67,70,73],{},[56,68,69],{},"호스트(Host)",[56,71,72],{},"네트워크에 연결되어 통신하는 컴퓨터나 장치",[56,74,75],{},"내 노트북, 웹 서버, 스마트폰",[38,77,78,81,84],{},[56,79,80],{},"클라이언트(Client)",[56,82,83],{},"서비스를 요청하고 사용하는 프로그램",[56,85,86],{},"웹 브라우저, 채팅 앱",[38,88,89,92,95],{},[56,90,91],{},"서버(Server)",[56,93,94],{},"클라이언트의 요청을 기다리고 서비스를 제공하는 프로그램",[56,96,97],{},"웹 서버, 채팅 서버",[38,99,100,103,106],{},[56,101,102],{},"IP 주소",[56,104,105],{},"네트워크에서 컴퓨터를 식별하는 주소",[56,107,108,112,113],{},[109,110,111],"code",{},"192.168.0.10",", ",[109,114,115],{},"127.0.0.1",[38,117,118,123,126],{},[56,119,120],{},[109,121,122],{},"localhost",[56,124,125],{},"현재 사용 중인 컴퓨터를 가리키는 이름",[56,127,128],{},"내 컴퓨터에서 실행한 서버에 접속할 때 사용",[38,130,131,134,137],{},[56,132,133],{},"포트(Port)",[56,135,136],{},"한 컴퓨터 안에서 통신할 프로그램을 구분하는 번호",[56,138,139,142],{},[109,140,141],{},"8080"," 포트에서 실행 중인 서버",[38,144,145,148,151],{},[56,146,147],{},"프로토콜(Protocol)",[56,149,150],{},"통신할 때 지켜야 하는 약속",[56,152,153],{},"데이터를 어떤 순서와 형식으로 주고받을지 정하는 규칙",[38,155,156,159,162],{},[56,157,158],{},"TCP",[56,160,161],{},"연결을 먼저 만들고, 데이터의 순서와 전달을 확인하는 통신 방식",[56,163,164],{},"상대방에게 메시지가 정확히 도착해야 하는 채팅",[38,166,167,170,173],{},[56,168,169],{},"UDP",[56,171,172],{},"연결 과정 없이 빠르게 데이터를 보내는 통신 방식",[56,174,175],{},"약간의 손실보다 빠른 전송이 중요한 실시간 영상",[38,177,178,181,184],{},[56,179,180],{},"소켓(Socket)",[56,182,183],{},"두 프로그램 사이의 통신 연결을 표현하는 객체 또는 통신 끝점",[56,185,186],{},"서버와 클라이언트가 메시지를 주고받는 통로",[38,188,189,192,195],{},[56,190,191],{},"서버 소켓(ServerSocket)",[56,193,194],{},"서버가 특정 포트에서 클라이언트 연결을 기다리기 위한 객체",[56,196,197],{},"식당 입구에서 손님을 기다리는 직원",[38,199,200,203,206],{},[56,201,202],{},"스트림(Stream)",[56,204,205],{},"데이터를 순서대로 읽거나 쓰는 통로",[56,207,208],{},"물이 흐르듯 바이트나 문자가 차례대로 이동하는 통로",[38,210,211,214,217],{},[56,212,213],{},"바이트(Byte)",[56,215,216],{},"컴퓨터가 데이터를 처리하는 기본 단위 중 하나",[56,218,219],{},"문자나 파일을 네트워크로 전송할 때의 데이터 단위",[38,221,222,225,228],{},[56,223,224],{},"바인딩(Binding)",[56,226,227],{},"서버 소켓을 특정 포트에 연결하는 것",[56,229,230,231,233],{},"서버가 ",[109,232,141],{},"번 방을 사용하겠다고 예약하는 것",[38,235,236,239,242],{},[56,237,238],{},"리스닝(Listening)",[56,240,241],{},"서버가 클라이언트의 연결 요청을 기다리는 상태",[56,243,244],{},"식당이 손님을 받을 준비를 하고 있는 상태",[38,246,247,252,255],{},[56,248,249],{},[109,250,251],{},"accept()",[56,253,254],{},"연결 요청을 기다리다가 연결되면 통신용 소켓을 반환하는 메서드",[56,256,257],{},"대기 중인 손님을 맞이해 자리를 안내하는 동작",[38,259,260,263,266],{},[56,261,262],{},"파일 디스크립터",[56,264,265],{},"운영체제가 소켓 같은 입출력 자원에 부여하는 식별 번호",[56,267,268],{},"운영체제가 열린 통신 통로를 관리하기 위한 번호",[27,270,272],{"id":271},"소켓-통신에-사용되는-주소","소켓 통신에 사용되는 주소",[14,274,275],{},"소켓 연결은 보통 다음 세 가지 정보로 대상을 구분합니다.",[277,278,284],"pre",{"className":279,"code":281,"language":282,"meta":283},[280],"language-text","프로토콜 + IP 주소(또는 호스트 이름) + 포트 번호\n\nTCP + localhost + 8080\n","text","",[109,285,281],{"__ignoreMap":283},[14,287,288,289,292,293,295],{},"예를 들어 ",[109,290,291],{},"localhost:8080","은 현재 컴퓨터의 ",[109,294,141],{},"번 포트에서 기다리는 프로그램을 의미합니다.",[32,297,298,311],{},[35,299,300],{},[38,301,302,305,308],{},[41,303,304],{},"구성 요소",[41,306,307],{},"역할",[41,309,310],{},"예시",[51,312,313,323,337],{},[38,314,315,318,321],{},[56,316,317],{},"프로토콜",[56,319,320],{},"통신 규칙을 결정",[56,322,158],{},[38,324,325,328,331],{},[56,326,327],{},"호스트 주소",[56,329,330],{},"어느 컴퓨터에 연결할지 결정",[56,332,333,112,335],{},[109,334,122],{},[109,336,111],{},[38,338,339,342,345],{},[56,340,341],{},"포트 번호",[56,343,344],{},"그 컴퓨터의 어느 프로그램에 연결할지 결정",[56,346,347],{},[109,348,141],{},[27,350,352],{"id":351},"클라이언트와-서버의-연결-구조","클라이언트와 서버의 연결 구조",[14,354,355,356,358],{},"서버는 먼저 서버 소켓을 만들고 특정 포트에서 연결 요청을 기다립니다. 클라이언트가 연결을 요청하면 서버의 ",[109,357,251],{},"가 통신용 소켓을 반환합니다.",[14,360,361,362,365,366,369],{},"중요한 점은 ",[109,363,364],{},"ServerSocket","과 ",[109,367,368],{},"Socket","의 역할이 다르다는 것입니다.",[371,372,373,379],"ul",{},[374,375,376,378],"li",{},[109,377,364],{},": 새로운 클라이언트의 연결 요청을 기다립니다.",[374,380,381,383],{},[109,382,368],{},": 연결이 완료된 클라이언트와 실제 데이터를 주고받습니다.",[277,385,389],{"className":386,"code":387,"language":388,"meta":283,"style":283},"language-mermaid shiki shiki-themes github-light github-dark","sequenceDiagram\n    participant C as 클라이언트 프로그램\n    participant S as 서버 프로그램\n    participant SS as ServerSocket\n    participant CS as 통신용 Socket\n\n    S->>SS: ServerSocket(8080) 생성\n    SS-->>S: 8080 포트에서 대기\n    C->>SS: localhost:8080 연결 요청\n    S->>SS: accept() 호출\n    SS->>CS: 클라이언트 전용 Socket 생성\n    CS-->>S: 연결된 Socket 반환\n    C->>CS: 데이터 전송\n    CS-->>S: 데이터 수신\n    S->>CS: 응답 데이터 전송\n    CS-->>C: 응답 수신\n","mermaid",[109,390,391,399,405,411,417,423,430,436,442,448,454,460,466,472,478,484],{"__ignoreMap":283},[392,393,396],"span",{"class":394,"line":395},"line",1,[392,397,398],{},"sequenceDiagram\n",[392,400,402],{"class":394,"line":401},2,[392,403,404],{},"    participant C as 클라이언트 프로그램\n",[392,406,408],{"class":394,"line":407},3,[392,409,410],{},"    participant S as 서버 프로그램\n",[392,412,414],{"class":394,"line":413},4,[392,415,416],{},"    participant SS as ServerSocket\n",[392,418,420],{"class":394,"line":419},5,[392,421,422],{},"    participant CS as 통신용 Socket\n",[392,424,426],{"class":394,"line":425},6,[392,427,429],{"emptyLinePlaceholder":428},true,"\n",[392,431,433],{"class":394,"line":432},7,[392,434,435],{},"    S->>SS: ServerSocket(8080) 생성\n",[392,437,439],{"class":394,"line":438},8,[392,440,441],{},"    SS-->>S: 8080 포트에서 대기\n",[392,443,445],{"class":394,"line":444},9,[392,446,447],{},"    C->>SS: localhost:8080 연결 요청\n",[392,449,451],{"class":394,"line":450},10,[392,452,453],{},"    S->>SS: accept() 호출\n",[392,455,457],{"class":394,"line":456},11,[392,458,459],{},"    SS->>CS: 클라이언트 전용 Socket 생성\n",[392,461,463],{"class":394,"line":462},12,[392,464,465],{},"    CS-->>S: 연결된 Socket 반환\n",[392,467,469],{"class":394,"line":468},13,[392,470,471],{},"    C->>CS: 데이터 전송\n",[392,473,475],{"class":394,"line":474},14,[392,476,477],{},"    CS-->>S: 데이터 수신\n",[392,479,481],{"class":394,"line":480},15,[392,482,483],{},"    S->>CS: 응답 데이터 전송\n",[392,485,487],{"class":394,"line":486},16,[392,488,489],{},"    CS-->>C: 응답 수신\n",[27,491,493],{"id":492},"java에서-사용하는-주요-클래스","Java에서 사용하는 주요 클래스",[495,496,498],"h4",{"id":497},"inetaddress",[109,499,500],{},"InetAddress",[14,502,503,506],{},[109,504,505],{},"java.net.InetAddress","는 호스트 이름과 IP 주소 정보를 표현하는 클래스입니다. 도메인 이름을 IP 주소로 바꾸거나 현재 컴퓨터의 주소를 확인할 때 사용합니다.",[32,508,509,521],{},[35,510,511],{},[38,512,513,516,519],{},[41,514,515],{},"메서드",[41,517,518],{},"기능",[41,520,49],{},[51,522,523,541,554,569],{},[38,524,525,530,536],{},[56,526,527],{},[109,528,529],{},"InetAddress.getByName(host)",[56,531,532,533,535],{},"호스트 이름을 조회해 ",[109,534,500],{}," 객체 반환",[56,537,538,540],{},[109,539,122],{},"의 IP 주소 확인",[38,542,543,548,551],{},[56,544,545],{},[109,546,547],{},"InetAddress.getLocalHost()",[56,549,550],{},"현재 컴퓨터의 호스트 정보 반환",[56,552,553],{},"내 컴퓨터 이름과 IP 확인",[38,555,556,561,564],{},[56,557,558],{},[109,559,560],{},"getHostAddress()",[56,562,563],{},"IP 주소를 문자열로 반환",[56,565,566,568],{},[109,567,115],{}," 출력",[38,570,571,576,579],{},[56,572,573],{},[109,574,575],{},"getHostName()",[56,577,578],{},"호스트 이름을 문자열로 반환",[56,580,581,568],{},[109,582,122],{},[495,584,586],{"id":585},"socket",[109,587,368],{},[14,589,590,593],{},[109,591,592],{},"java.net.Socket","은 TCP 클라이언트가 서버와 연결된 뒤 데이터를 주고받는 통신용 객체입니다.",[32,595,596,605],{},[35,597,598],{},[38,599,600,603],{},[41,601,602],{},"생성자 또는 메서드",[41,604,518],{},[51,606,607,617,627,637],{},[38,608,609,614],{},[56,610,611],{},[109,612,613],{},"new Socket(host, port)",[56,615,616],{},"지정한 호스트와 포트에 TCP 연결 요청",[38,618,619,624],{},[56,620,621],{},[109,622,623],{},"getInputStream()",[56,625,626],{},"서버에서 클라이언트로 들어오는 데이터 읽기",[38,628,629,634],{},[56,630,631],{},[109,632,633],{},"getOutputStream()",[56,635,636],{},"클라이언트에서 서버로 나가는 데이터 쓰기",[38,638,639,644],{},[56,640,641],{},[109,642,643],{},"close()",[56,645,646],{},"소켓 연결 종료",[495,648,650],{"id":649},"serversocket",[109,651,364],{},[14,653,654,657],{},[109,655,656],{},"java.net.ServerSocket","은 TCP 서버가 특정 포트에서 클라이언트 연결을 기다릴 때 사용하는 객체입니다.",[32,659,660,668],{},[35,661,662],{},[38,663,664,666],{},[41,665,602],{},[41,667,518],{},[51,669,670,680,692],{},[38,671,672,677],{},[56,673,674],{},[109,675,676],{},"new ServerSocket(port)",[56,678,679],{},"지정한 포트에 서버 소켓을 열고 연결을 받을 준비",[38,681,682,686],{},[56,683,684],{},[109,685,251],{},[56,687,688,689,691],{},"클라이언트 연결을 기다리고, 연결되면 ",[109,690,368],{}," 반환",[38,693,694,698],{},[56,695,696],{},[109,697,643],{},[56,699,700],{},"서버 소켓을 닫고 새로운 연결을 받지 않음",[27,702,704],{"id":703},"java-tcp-에코-서버-예제","Java TCP 에코 서버 예제",[14,706,707],{},"에코 서버는 클라이언트가 보낸 메시지를 그대로 다시 돌려주는 서버입니다.",[495,709,711,712],{"id":710},"서버-코드-simpleechoserverjava","서버 코드: ",[109,713,714],{},"SimpleEchoServer.java",[277,716,720],{"className":717,"code":718,"language":719,"meta":283,"style":283},"language-java shiki shiki-themes github-light github-dark","import java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.net.ServerSocket;\nimport java.net.Socket;\n\npublic class SimpleEchoServer {\n    public static void main(String[] args) throws IOException {\n        int port = 8080;\n\n        \u002F\u002F ServerSocket: 서버가 클라이언트 연결을 기다리는 객체\n        \u002F\u002F 8080 포트를 사용하겠다고 운영체제에 등록한다.\n        try (ServerSocket serverSocket = new ServerSocket(port)) {\n            System.out.println(\"Echo Server started on port \" + port);\n\n            \u002F\u002F 여러 클라이언트의 접속을 계속 기다린다.\n            while (true) {\n                \u002F\u002F accept(): 클라이언트 연결 요청이 올 때까지 대기한다.\n                \u002F\u002F 연결되면 해당 클라이언트와 통신할 Socket을 반환한다.\n                try (Socket clientSocket = serverSocket.accept();\n                     \u002F\u002F InputStream: 클라이언트가 보낸 바이트 데이터를 받는 통로\n                     BufferedReader reader = new BufferedReader(\n                         new InputStreamReader(clientSocket.getInputStream()));\n                     \u002F\u002F OutputStream: 클라이언트로 데이터를 보내는 통로\n                     PrintWriter writer = new PrintWriter(\n                         clientSocket.getOutputStream(), true)) {\n\n                    System.out.println(\"Client connected: \"\n                        + clientSocket.getInetAddress());\n\n                    \u002F\u002F readLine(): 클라이언트가 보낸 한 줄을 읽는다.\n                    String message = reader.readLine();\n                    System.out.println(\"Received: \" + message);\n\n                    \u002F\u002F println(): 메시지를 전송하고 줄바꿈까지 보낸다.\n                    \u002F\u002F true 옵션 덕분에 출력 버퍼를 즉시 비운다(auto-flush).\n                    writer.println(\"Echo: \" + message);\n                }\n                \u002F\u002F try-with-resources가 끝나면 clientSocket도 자동으로 닫힌다.\n            }\n        }\n    }\n}\n","java",[109,721,722,727,732,737,742,747,752,756,761,766,771,775,780,785,790,795,799,805,811,817,823,829,835,841,847,853,859,865,870,876,882,887,893,899,905,910,916,922,928,934,940,946,952,958],{"__ignoreMap":283},[392,723,724],{"class":394,"line":395},[392,725,726],{},"import java.io.BufferedReader;\n",[392,728,729],{"class":394,"line":401},[392,730,731],{},"import java.io.IOException;\n",[392,733,734],{"class":394,"line":407},[392,735,736],{},"import java.io.InputStreamReader;\n",[392,738,739],{"class":394,"line":413},[392,740,741],{},"import java.io.PrintWriter;\n",[392,743,744],{"class":394,"line":419},[392,745,746],{},"import java.net.ServerSocket;\n",[392,748,749],{"class":394,"line":425},[392,750,751],{},"import java.net.Socket;\n",[392,753,754],{"class":394,"line":432},[392,755,429],{"emptyLinePlaceholder":428},[392,757,758],{"class":394,"line":438},[392,759,760],{},"public class SimpleEchoServer {\n",[392,762,763],{"class":394,"line":444},[392,764,765],{},"    public static void main(String[] args) throws IOException {\n",[392,767,768],{"class":394,"line":450},[392,769,770],{},"        int port = 8080;\n",[392,772,773],{"class":394,"line":456},[392,774,429],{"emptyLinePlaceholder":428},[392,776,777],{"class":394,"line":462},[392,778,779],{},"        \u002F\u002F ServerSocket: 서버가 클라이언트 연결을 기다리는 객체\n",[392,781,782],{"class":394,"line":468},[392,783,784],{},"        \u002F\u002F 8080 포트를 사용하겠다고 운영체제에 등록한다.\n",[392,786,787],{"class":394,"line":474},[392,788,789],{},"        try (ServerSocket serverSocket = new ServerSocket(port)) {\n",[392,791,792],{"class":394,"line":480},[392,793,794],{},"            System.out.println(\"Echo Server started on port \" + port);\n",[392,796,797],{"class":394,"line":486},[392,798,429],{"emptyLinePlaceholder":428},[392,800,802],{"class":394,"line":801},17,[392,803,804],{},"            \u002F\u002F 여러 클라이언트의 접속을 계속 기다린다.\n",[392,806,808],{"class":394,"line":807},18,[392,809,810],{},"            while (true) {\n",[392,812,814],{"class":394,"line":813},19,[392,815,816],{},"                \u002F\u002F accept(): 클라이언트 연결 요청이 올 때까지 대기한다.\n",[392,818,820],{"class":394,"line":819},20,[392,821,822],{},"                \u002F\u002F 연결되면 해당 클라이언트와 통신할 Socket을 반환한다.\n",[392,824,826],{"class":394,"line":825},21,[392,827,828],{},"                try (Socket clientSocket = serverSocket.accept();\n",[392,830,832],{"class":394,"line":831},22,[392,833,834],{},"                     \u002F\u002F InputStream: 클라이언트가 보낸 바이트 데이터를 받는 통로\n",[392,836,838],{"class":394,"line":837},23,[392,839,840],{},"                     BufferedReader reader = new BufferedReader(\n",[392,842,844],{"class":394,"line":843},24,[392,845,846],{},"                         new InputStreamReader(clientSocket.getInputStream()));\n",[392,848,850],{"class":394,"line":849},25,[392,851,852],{},"                     \u002F\u002F OutputStream: 클라이언트로 데이터를 보내는 통로\n",[392,854,856],{"class":394,"line":855},26,[392,857,858],{},"                     PrintWriter writer = new PrintWriter(\n",[392,860,862],{"class":394,"line":861},27,[392,863,864],{},"                         clientSocket.getOutputStream(), true)) {\n",[392,866,868],{"class":394,"line":867},28,[392,869,429],{"emptyLinePlaceholder":428},[392,871,873],{"class":394,"line":872},29,[392,874,875],{},"                    System.out.println(\"Client connected: \"\n",[392,877,879],{"class":394,"line":878},30,[392,880,881],{},"                        + clientSocket.getInetAddress());\n",[392,883,885],{"class":394,"line":884},31,[392,886,429],{"emptyLinePlaceholder":428},[392,888,890],{"class":394,"line":889},32,[392,891,892],{},"                    \u002F\u002F readLine(): 클라이언트가 보낸 한 줄을 읽는다.\n",[392,894,896],{"class":394,"line":895},33,[392,897,898],{},"                    String message = reader.readLine();\n",[392,900,902],{"class":394,"line":901},34,[392,903,904],{},"                    System.out.println(\"Received: \" + message);\n",[392,906,908],{"class":394,"line":907},35,[392,909,429],{"emptyLinePlaceholder":428},[392,911,913],{"class":394,"line":912},36,[392,914,915],{},"                    \u002F\u002F println(): 메시지를 전송하고 줄바꿈까지 보낸다.\n",[392,917,919],{"class":394,"line":918},37,[392,920,921],{},"                    \u002F\u002F true 옵션 덕분에 출력 버퍼를 즉시 비운다(auto-flush).\n",[392,923,925],{"class":394,"line":924},38,[392,926,927],{},"                    writer.println(\"Echo: \" + message);\n",[392,929,931],{"class":394,"line":930},39,[392,932,933],{},"                }\n",[392,935,937],{"class":394,"line":936},40,[392,938,939],{},"                \u002F\u002F try-with-resources가 끝나면 clientSocket도 자동으로 닫힌다.\n",[392,941,943],{"class":394,"line":942},41,[392,944,945],{},"            }\n",[392,947,949],{"class":394,"line":948},42,[392,950,951],{},"        }\n",[392,953,955],{"class":394,"line":954},43,[392,956,957],{},"    }\n",[392,959,961],{"class":394,"line":960},44,[392,962,963],{},"}\n",[495,965,967,968],{"id":966},"클라이언트-코드-simpleechoclientjava","클라이언트 코드: ",[109,969,970],{},"SimpleEchoClient.java",[277,972,974],{"className":717,"code":973,"language":719,"meta":283,"style":283},"import java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.net.Socket;\n\npublic class SimpleEchoClient {\n    public static void main(String[] args) throws IOException {\n        String host = \"localhost\";\n        int port = 8080;\n\n        \u002F\u002F Socket: 서버의 host와 port에 TCP 연결을 요청하는 객체\n        \u002F\u002F localhost는 현재 컴퓨터를 의미한다.\n        try (Socket socket = new Socket(host, port);\n             \u002F\u002F 서버에서 오는 데이터를 읽는 입력 통로\n             BufferedReader reader = new BufferedReader(\n                 new InputStreamReader(socket.getInputStream()));\n             \u002F\u002F 서버로 데이터를 보내는 출력 통로\n             PrintWriter writer = new PrintWriter(\n                 socket.getOutputStream(), true)) {\n\n            \u002F\u002F println(): 서버로 한 줄의 메시지를 전송한다.\n            writer.println(\"Hello Server!\");\n\n            \u002F\u002F readLine(): 서버가 보낸 에코 응답을 한 줄 읽는다.\n            String response = reader.readLine();\n            System.out.println(\"Response: \" + response);\n        }\n        \u002F\u002F try-with-resources가 끝나면 소켓과 스트림이 자동으로 닫힌다.\n    }\n}\n",[109,975,976,980,984,988,992,996,1000,1005,1009,1014,1018,1022,1027,1032,1037,1042,1047,1052,1057,1062,1067,1071,1076,1081,1085,1090,1095,1100,1104,1109,1113],{"__ignoreMap":283},[392,977,978],{"class":394,"line":395},[392,979,726],{},[392,981,982],{"class":394,"line":401},[392,983,731],{},[392,985,986],{"class":394,"line":407},[392,987,736],{},[392,989,990],{"class":394,"line":413},[392,991,741],{},[392,993,994],{"class":394,"line":419},[392,995,751],{},[392,997,998],{"class":394,"line":425},[392,999,429],{"emptyLinePlaceholder":428},[392,1001,1002],{"class":394,"line":432},[392,1003,1004],{},"public class SimpleEchoClient {\n",[392,1006,1007],{"class":394,"line":438},[392,1008,765],{},[392,1010,1011],{"class":394,"line":444},[392,1012,1013],{},"        String host = \"localhost\";\n",[392,1015,1016],{"class":394,"line":450},[392,1017,770],{},[392,1019,1020],{"class":394,"line":456},[392,1021,429],{"emptyLinePlaceholder":428},[392,1023,1024],{"class":394,"line":462},[392,1025,1026],{},"        \u002F\u002F Socket: 서버의 host와 port에 TCP 연결을 요청하는 객체\n",[392,1028,1029],{"class":394,"line":468},[392,1030,1031],{},"        \u002F\u002F localhost는 현재 컴퓨터를 의미한다.\n",[392,1033,1034],{"class":394,"line":474},[392,1035,1036],{},"        try (Socket socket = new Socket(host, port);\n",[392,1038,1039],{"class":394,"line":480},[392,1040,1041],{},"             \u002F\u002F 서버에서 오는 데이터를 읽는 입력 통로\n",[392,1043,1044],{"class":394,"line":486},[392,1045,1046],{},"             BufferedReader reader = new BufferedReader(\n",[392,1048,1049],{"class":394,"line":801},[392,1050,1051],{},"                 new InputStreamReader(socket.getInputStream()));\n",[392,1053,1054],{"class":394,"line":807},[392,1055,1056],{},"             \u002F\u002F 서버로 데이터를 보내는 출력 통로\n",[392,1058,1059],{"class":394,"line":813},[392,1060,1061],{},"             PrintWriter writer = new PrintWriter(\n",[392,1063,1064],{"class":394,"line":819},[392,1065,1066],{},"                 socket.getOutputStream(), true)) {\n",[392,1068,1069],{"class":394,"line":825},[392,1070,429],{"emptyLinePlaceholder":428},[392,1072,1073],{"class":394,"line":831},[392,1074,1075],{},"            \u002F\u002F println(): 서버로 한 줄의 메시지를 전송한다.\n",[392,1077,1078],{"class":394,"line":837},[392,1079,1080],{},"            writer.println(\"Hello Server!\");\n",[392,1082,1083],{"class":394,"line":843},[392,1084,429],{"emptyLinePlaceholder":428},[392,1086,1087],{"class":394,"line":849},[392,1088,1089],{},"            \u002F\u002F readLine(): 서버가 보낸 에코 응답을 한 줄 읽는다.\n",[392,1091,1092],{"class":394,"line":855},[392,1093,1094],{},"            String response = reader.readLine();\n",[392,1096,1097],{"class":394,"line":861},[392,1098,1099],{},"            System.out.println(\"Response: \" + response);\n",[392,1101,1102],{"class":394,"line":867},[392,1103,951],{},[392,1105,1106],{"class":394,"line":872},[392,1107,1108],{},"        \u002F\u002F try-with-resources가 끝나면 소켓과 스트림이 자동으로 닫힌다.\n",[392,1110,1111],{"class":394,"line":878},[392,1112,957],{},[392,1114,1115],{"class":394,"line":884},[392,1116,963],{},[27,1118,1120],{"id":1119},"코드-실행-흐름","코드 실행 흐름",[14,1122,1123],{},"서버와 클라이언트는 각각 별도의 터미널에서 실행해야 합니다.",[277,1125,1127],{"className":386,"code":1126,"language":388,"meta":283,"style":283},"flowchart LR\n    A[서버 실행] --> B[ServerSocket 생성]\n    B --> C[8080 포트에서 accept 대기]\n    D[클라이언트 실행] --> E[Socket 생성]\n    E --> F[localhost:8080 연결 요청]\n    F --> C\n    C --> G[클라이언트 전용 Socket 반환]\n    G --> H[클라이언트 writer.println]\n    H --> I[서버 reader.readLine]\n    I --> J[서버 writer.println Echo 응답]\n    J --> K[클라이언트 reader.readLine]\n    K --> L[응답 출력 및 연결 종료]\n",[109,1128,1129,1134,1139,1144,1149,1154,1159,1164,1169,1174,1179,1184],{"__ignoreMap":283},[392,1130,1131],{"class":394,"line":395},[392,1132,1133],{},"flowchart LR\n",[392,1135,1136],{"class":394,"line":401},[392,1137,1138],{},"    A[서버 실행] --> B[ServerSocket 생성]\n",[392,1140,1141],{"class":394,"line":407},[392,1142,1143],{},"    B --> C[8080 포트에서 accept 대기]\n",[392,1145,1146],{"class":394,"line":413},[392,1147,1148],{},"    D[클라이언트 실행] --> E[Socket 생성]\n",[392,1150,1151],{"class":394,"line":419},[392,1152,1153],{},"    E --> F[localhost:8080 연결 요청]\n",[392,1155,1156],{"class":394,"line":425},[392,1157,1158],{},"    F --> C\n",[392,1160,1161],{"class":394,"line":432},[392,1162,1163],{},"    C --> G[클라이언트 전용 Socket 반환]\n",[392,1165,1166],{"class":394,"line":438},[392,1167,1168],{},"    G --> H[클라이언트 writer.println]\n",[392,1170,1171],{"class":394,"line":444},[392,1172,1173],{},"    H --> I[서버 reader.readLine]\n",[392,1175,1176],{"class":394,"line":450},[392,1177,1178],{},"    I --> J[서버 writer.println Echo 응답]\n",[392,1180,1181],{"class":394,"line":456},[392,1182,1183],{},"    J --> K[클라이언트 reader.readLine]\n",[392,1185,1186],{"class":394,"line":462},[392,1187,1188],{},"    K --> L[응답 출력 및 연결 종료]\n",[495,1190,1192],{"id":1191},"실행-명령","실행 명령",[14,1194,1195],{},"먼저 두 Java 파일을 같은 폴더에 저장하고 컴파일합니다.",[277,1197,1201],{"className":1198,"code":1199,"language":1200,"meta":283,"style":283},"language-bash shiki shiki-themes github-light github-dark","javac SimpleEchoServer.java SimpleEchoClient.java\n","bash",[109,1202,1203],{"__ignoreMap":283},[392,1204,1205,1209,1213],{"class":394,"line":395},[392,1206,1208],{"class":1207},"sScJk","javac",[392,1210,1212],{"class":1211},"sZZnC"," SimpleEchoServer.java",[392,1214,1215],{"class":1211}," SimpleEchoClient.java\n",[14,1217,1218],{},"첫 번째 터미널에서 서버를 실행합니다.",[277,1220,1222],{"className":1198,"code":1221,"language":1200,"meta":283,"style":283},"java SimpleEchoServer\n",[109,1223,1224],{"__ignoreMap":283},[392,1225,1226,1228],{"class":394,"line":395},[392,1227,719],{"class":1207},[392,1229,1230],{"class":1211}," SimpleEchoServer\n",[14,1232,1233],{},"두 번째 터미널에서 클라이언트를 실행합니다.",[277,1235,1237],{"className":1198,"code":1236,"language":1200,"meta":283,"style":283},"java SimpleEchoClient\n",[109,1238,1239],{"__ignoreMap":283},[392,1240,1241,1243],{"class":394,"line":395},[392,1242,719],{"class":1207},[392,1244,1245],{"class":1211}," SimpleEchoClient\n",[495,1247,1249],{"id":1248},"예상-결과","예상 결과",[14,1251,1252],{},"서버 터미널:",[277,1254,1257],{"className":1255,"code":1256,"language":282,"meta":283},[280],"Echo Server started on port 8080\nClient connected: \u002F127.0.0.1\nReceived: Hello Server!\n",[109,1258,1256],{"__ignoreMap":283},[14,1260,1261],{},"클라이언트 터미널:",[277,1263,1266],{"className":1264,"code":1265,"language":282,"meta":283},[280],"Response: Echo: Hello Server!\n",[109,1267,1265],{"__ignoreMap":283},[27,1269,1271],{"id":1270},"코드에서-데이터가-이동하는-방향","코드에서 데이터가 이동하는 방향",[277,1273,1275],{"className":386,"code":1274,"language":388,"meta":283,"style":283},"flowchart TB\n    subgraph Client[클라이언트]\n        CW[PrintWriter\\nwriter.println]\n        CR[BufferedReader\\nreader.readLine]\n    end\n    subgraph Server[서버]\n        SR[BufferedReader\\nreader.readLine]\n        SW[PrintWriter\\nwriter.println]\n    end\n\n    CW -- \"Hello Server!\" --> SR\n    SW -- \"Echo: Hello Server!\" --> CR\n",[109,1276,1277,1282,1287,1292,1297,1302,1307,1312,1317,1321,1325,1330],{"__ignoreMap":283},[392,1278,1279],{"class":394,"line":395},[392,1280,1281],{},"flowchart TB\n",[392,1283,1284],{"class":394,"line":401},[392,1285,1286],{},"    subgraph Client[클라이언트]\n",[392,1288,1289],{"class":394,"line":407},[392,1290,1291],{},"        CW[PrintWriter\\nwriter.println]\n",[392,1293,1294],{"class":394,"line":413},[392,1295,1296],{},"        CR[BufferedReader\\nreader.readLine]\n",[392,1298,1299],{"class":394,"line":419},[392,1300,1301],{},"    end\n",[392,1303,1304],{"class":394,"line":425},[392,1305,1306],{},"    subgraph Server[서버]\n",[392,1308,1309],{"class":394,"line":432},[392,1310,1311],{},"        SR[BufferedReader\\nreader.readLine]\n",[392,1313,1314],{"class":394,"line":438},[392,1315,1316],{},"        SW[PrintWriter\\nwriter.println]\n",[392,1318,1319],{"class":394,"line":444},[392,1320,1301],{},[392,1322,1323],{"class":394,"line":450},[392,1324,429],{"emptyLinePlaceholder":428},[392,1326,1327],{"class":394,"line":456},[392,1328,1329],{},"    CW -- \"Hello Server!\" --> SR\n",[392,1331,1332],{"class":394,"line":462},[392,1333,1334],{},"    SW -- \"Echo: Hello Server!\" --> CR\n",[27,1336,1338],{"id":1337},"실행-순서-요약","실행 순서 요약",[32,1340,1341,1355],{},[35,1342,1343],{},[38,1344,1345,1349,1352],{},[41,1346,1348],{"align":1347},"right","순서",[41,1350,1351],{},"실행 주체",[41,1353,1354],{},"동작",[51,1356,1357,1373,1385,1400,1413,1426,1439,1452,1462],{},[38,1358,1359,1362,1365],{},[56,1360,1361],{"align":1347},"1",[56,1363,1364],{},"서버",[56,1366,1367,1369,1370,1372],{},[109,1368,364],{},"으로 ",[109,1371,141],{}," 포트를 연다",[38,1374,1375,1378,1380],{},[56,1376,1377],{"align":1347},"2",[56,1379,1364],{},[56,1381,1382,1384],{},[109,1383,251],{},"로 클라이언트 연결을 기다린다",[38,1386,1387,1390,1393],{},[56,1388,1389],{"align":1347},"3",[56,1391,1392],{},"클라이언트",[56,1394,1395,1369,1397,1399],{},[109,1396,368],{},[109,1398,291],{},"에 연결한다",[38,1401,1402,1405,1407],{},[56,1403,1404],{"align":1347},"4",[56,1406,1364],{},[56,1408,1409,1410,1412],{},"연결된 클라이언트 전용 ",[109,1411,368],{},"을 얻는다",[38,1414,1415,1418,1420],{},[56,1416,1417],{"align":1347},"5",[56,1419,1392],{},[56,1421,1422,1425],{},[109,1423,1424],{},"writer.println()","으로 메시지를 보낸다",[38,1427,1428,1431,1433],{},[56,1429,1430],{"align":1347},"6",[56,1432,1364],{},[56,1434,1435,1438],{},[109,1436,1437],{},"reader.readLine()","으로 메시지를 읽는다",[38,1440,1441,1444,1446],{},[56,1442,1443],{"align":1347},"7",[56,1445,1364],{},[56,1447,1448,1451],{},[109,1449,1450],{},"Echo:","를 붙여 응답을 보낸다",[38,1453,1454,1457,1459],{},[56,1455,1456],{"align":1347},"8",[56,1458,1392],{},[56,1460,1461],{},"응답을 읽고 화면에 출력한다",[38,1463,1464,1467,1470],{},[56,1465,1466],{"align":1347},"9",[56,1468,1469],{},"양쪽",[56,1471,1472],{},"스트림과 소켓을 닫는다",[27,1474,1475],{"id":1475},"정리",[371,1477,1478,1484,1490,1499,1509],{},[374,1479,1480,1481,1483],{},"서버는 ",[109,1482,364],{},"으로 연결 요청을 기다립니다.",[374,1485,1486,1487,1489],{},"클라이언트는 ",[109,1488,368],{},"으로 서버에 연결합니다.",[374,1491,1492,1493,1495,1496,1498],{},"서버의 ",[109,1494,251],{},"는 실제 통신에 사용할 새로운 ",[109,1497,368],{},"을 반환합니다.",[374,1500,1501,1504,1505,1508],{},[109,1502,1503],{},"InputStream"," 계열 객체는 데이터를 읽고, ",[109,1506,1507],{},"OutputStream"," 계열 객체는 데이터를 씁니다.",[374,1510,1511,1514],{},[109,1512,1513],{},"try-with-resources","를 사용하면 통신이 끝난 뒤 소켓과 스트림을 자동으로 닫을 수 있습니다.",[1516,1517,1518],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":283,"searchDepth":401,"depth":401,"links":1520},[1521],{"id":12,"depth":401,"text":5,"children":1522},[1523,1524,1525,1526,1527,1528,1529,1530,1531],{"id":29,"depth":407,"text":30},{"id":271,"depth":407,"text":272},{"id":351,"depth":407,"text":352},{"id":492,"depth":407,"text":493},{"id":703,"depth":407,"text":704},{"id":1119,"depth":407,"text":1120},{"id":1270,"depth":407,"text":1271},{"id":1337,"depth":407,"text":1338},{"id":1475,"depth":407,"text":1475},[1533,1534],"Backend","Network","2026-08-12 17:47:59 +0900","md",null,"\u002Fbackend\u002Fnetwork\u002F2026\u002F08\u002F12\u002FSocket\u002F",{"layout":1540},"post","\u002Fposts\u002Fbackend\u002Fnetwork()\u002Fsocket",{"title":5,"description":16},"posts\u002FBackend\u002FNetwork(중요)\u002FSocket",[],"LQNOFwGc7YVge_Qb0zdtLgZo3TkN8AtOeIUQxTmsGVA",1788744785542]