기록
day 0604 네트워크 프로그래밍 본문
네트워크 통신
: 서로 떨어져있는 컴퓨터끼리 통신하기위한 프로그램
자바에서는 네트워크 프로그래밍을 위하여
java.net 패키지에 관련 인터페이스와 클래스를 제공합니다
ip Address
: 네트워크 상에 있는 특정한 컴퓨터를 식별하기 위한 주소
내 컴퓨터의 ip 주소 확인하기 => ipconfig
port 번호
: 하나의 컴퓨터에서 여러개의 네트워크 프로그램이 동시에 실행 될 수 있어요
특정 프로그램의 식별자 역할
1) TCP 방식
=> 현실세계의 전화와 비슷하게 통신하는 방식
=> 통신을 할 상대방 컴퓨터와 연결이 이루어지고 난 다음에 그 연결된 회선을 통해서 데이터를 주고 받는 방식
장점) 신뢰성 높다
단점) 네트워크 부담이 높다
=> 자바가 TCP 방식을 위하여 제공하는 클래스
serverSocket, Socket
2) UDP 방식
=> 현실세계의 편지와 비슷하게 통신하는 방식
=> 통신을 할 상대방 컴퓨터와 연결을 맺지 않고 무조건 덮어놓고(?) 데이터를 보내는 방식
장점) 네트워크 부담이 낮다
단점) 신뢰성 떨어진다
=> UDP 방식을 위해서 자바가 제공하는 클래스
DatagramSocket, DatagramPacket
/InetAddress 는 생성자가 따로 없다/
package com.kosta.exam01;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressTest {
public static void main(String[] args) {
try {
// InetAddress addr = InetAddress.getByName("www.naver.com");
// System.out.println(addr);
InetAddress[] arr = InetAddress.getAllByName("www.naver.com");
for(InetAddress addr : arr) {
System.out.println(addr);
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
어,, 음,,, 티스토리에서 네이버 언급해도 도ㅣ,,ㄴㅏ,,?
https://m.hanbit.co.kr/store/books/new_book_list.html
package com.kosta.exam01;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
public class URLTest {
public static void main(String[] args) {
// byte로 data란 배열을 가져온다
byte[] data = new byte[200];
try {
URL url = new URL("https://m.hanbit.co.kr/store/books/new_book_list.html");
InputStream is = url.openStream();
String str = " ";
// 더이상 읽을게 없을때까지 계속 읽어들여라
while(is.read(data) != - 1) {
str += new String(data);
// 새로운 데이터를 받기위해 비워준다
Arrays.fill(data, (byte)0);
}
System.out.println(str);
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Server
: 네트워크상에서 서비스를 제공하는 컴퓨터 혹은 프로그램
Client
: 네트워크상에서 서비스를 제공받는 컴퓨터 혹은 프로그램
/데이터를 주고받는다/
<< TCP 방식의 프로그래밍 절차 >>
Server Client
1. ServerSocket 생성
2. Client의 접속을
무한대기 상태로 기다린다
3. Socket 객체를 생성하여 통신을 요청
4. accept 메소드가 호출되어
통신을 수락한다(Socket을 반환)
5. (공통) 서버와 클라이언트가 각각의 소켓을 통하여 Stream을 생성
6. (공통) 스트림을 통하여 데이터를 주고받는다
7. (공통) 사용했던 자원을 닫아준다
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
public class TCPServer01 {
public static void main(String[] args) {
Random r = new Random();
try {
ServerSocket server = new ServerSocket(9001);
System.out.println("통신 준비 완료!");
while(true) {
Socket socket = server.accept();
System.out.println("** 클라이언트가 연결되었습니다 **");
// socket을 통해 데이터를 보낸다
OutputStream os = socket.getOutputStream();
// 난수 만들기
for(int i = 1; i <= 10; i++) {
int n = r.nextInt(100) + 1;
os.write(n);
Thread.sleep(200);
}
System.out.println("데이터 전송 완료!");
os.close();
socket.close();
server.close();
}
} catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
}
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPClient01 {
public static void main(String[] args) {
try {
// ip주소, port번호
Socket socket = new Socket("172.30.1.35", 9001);
InputStream is = socket.getInputStream();
for(int i = 1; i <= 10; i++) {
int n = is.read();
System.out.println("서버로부터 수신된 데이터 : " + n);
}
is.close();
socket.close();
} catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
}
/데이터를 주고받는다/
/UDP 방식으로 보내려면 Packet을 만들어야한다 (실행 할 때마다 전달받겠다)/
<< UDP 방식의 프로그래밍 절차 >>
DatagramPacket 단위로 데이터를 주고받아요
void receive(DatagramPacket p) Receives a datagram packet from this socket.
void send(DatagramPacket p) Sends a datagram packet from this socket.
데이터를 받는 쪽 데이터를 보내는 쪽
Receiver Sender
1) DatagramSocket 생성 DatagramSocket 생성
2) DatagramPacket 생성 DatagramPacket 생성
3) send를 통해 데이터 전송
4) receive를 통해 데이터 수신
5) 사용했던 자원을 닫아준다 사용했던 자원을 닫아준다
데이터를 받는 쪽 : DatagramPacket(byte[] buf, int length)
데이터를 보내는 쪽 : DatagramPacket(byte[] buf, int length, InetAddress address, int port)
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.Arrays;
public class UDPReceiver {
public static void main(String[] args) {
try {
DatagramSocket socket = new DatagramSocket(9002);
// 실제 받아진 데이터는 배열에 저장된다
byte[] data = new byte[100];
DatagramPacket packet = new DatagramPacket(data, data.length);
while(true) {
socket.receive(packet);
String msg = new String(data);
System.out.println("수신된 데이터 : " + msg);
// data를 0으로 비운다 error가 나기때문에 (byte)로 캐스팅한다
Arrays.fill(data, (byte)0);
}
} catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
}
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class UDPSender {
// args[0] args[1]
// java UDPSender 172.30.1.35 hello?
public static void main(String[] args) {
try {
// 주소,포트가 있는 packet을 생성하기위해 비워준다 ();
DatagramSocket socket = new DatagramSocket();
// packet 만들 준비
InetAddress addr = InetAddress.getByName(args[0]);
int port = 9002;
// 문자열을 byte형 배열로 만들어준다 (pebket이 byte형 배열을 원한다)
byte[] data = args[1].getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length, addr, port);
socket.send(packet);
socket.close();
} catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
}
/chat 화면 구성하기/
package com.kosta.chat01;
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class TCPChatClient extends JFrame {
// panel 1개, borderlayout, center/south
JTextArea jta;
JTextField jtf;
public TCPChatClient() {
jta = new JTextArea();
jtf = new JTextField(50);
JScrollPane jsp = new JScrollPane(jta);
JButton btnSend = new JButton("전송");
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
p.add(jtf, BorderLayout.CENTER);
p.add(btnSend, BorderLayout.EAST);
add(jsp, BorderLayout.CENTER);
add(p, BorderLayout.SOUTH);
setSize(400,300);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new TCPChatClient();
}
}
package com.kosta.chat01;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
public class TCPChatServer {
public static void main(String[] args) {
// 클라이언트로부터 수신된 데이터를 받기 위한 배열을 만든다
byte[] data = new byte[100];
try {
// 서버 소켓을 생성, 포트번호 9003
ServerSocket server = new ServerSocket(9005);
// 클라이언트의 접속을 무한대기상태로 기다린다
while(true) {
// 클라이언트에 접속을 수락
Socket socket = server.accept();
// 데이터 입출력을 위한 스트림
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
// 연결된 클라이언트와 계속 통신한다
// 혼자 대화, 여러명은 Thread 사용
while(true) {
is.read(data ); // 수신된 데이터를
os.write(data); // 그대로 클라이언트에게 보낸다
String msg = new String(data);
System.out.println("수신된 데이터 : " + msg);
Arrays.fill(data, (byte)0);
}
}
} catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
}
package com.kosta.chat01;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Arrays;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class TCPChatClient extends JFrame {
// panel 1개, borderlayout, center/south
JTextArea jta;
JTextField jtf;
// Socket과 입출력을 위한 스트림을 멤버번수로 선언
Socket socket;
InputStream is;
OutputStream os;
public TCPChatClient() {
try {
// 1. 서버와 통신하기위한 소켓 생성(ip주소, port번호)
socket = new Socket("172.30.1.35", 9005);
// 2. 생성된 소켓을 통해 스트림 생성한다
is = socket.getInputStream();
os = socket.getOutputStream(); // 문자열을 byte 단위로 보낸다
jta = new JTextArea();
jtf = new JTextField(50);
JScrollPane jsp = new JScrollPane(jta);
JButton btnSend = new JButton("전송"); // 데이터를 보낸다
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
p.add(jtf, BorderLayout.CENTER);
p.add(btnSend, BorderLayout.EAST);
add(jsp, BorderLayout.CENTER);
add(p, BorderLayout.SOUTH);
setSize(300,200);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 서버로부터 수신된 데이터를 계속 받기위한 쓰레드
class ClientThread extends Thread{
byte[] data = new byte[100];
@Override
public void run() {
// 서버 데이터를 받아 텍스트 에리어에 출력
try {
while(true) {
is.read(data);
jta.append(new String(data));
jta.append("\n");
Arrays.fill(data, (byte)0);
}
}catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
}
ClientThread ct = new ClientThread();
ct.start(); // 쓰레드 가동
// 데이터를 보낼 전송 버튼의 이벤트
btnSend.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 보낼 데이터를 byte형의 배열로 갖고온다
// getBytes(); 텍스트에 써진걸 byte형으로 바꾼다
byte[] data = jtf.getText().getBytes();
try {
// 보내는 데이터 : os
os.write(data);
}catch (Exception ex) {
System.out.println("예외발생 : " + ex.getMessage());
}
}
});
} catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
public static void main(String[] args) {
new TCPChatClient();
}
}
/혼자 대화하는 구조라 동시에 수행할 수 없다/
class ServerThread extends Thread {
Socket socket;
InputStream is;
OutputStream os;
public ServerThread(Socket socket){
// 데이터 입출력을 위한 스트림
try {
this.socket = socket;
is = socket.getInputStream();
os = socket.getOutputStream();
} catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
@Override
public void run() {
// 클라이언트로부터 수신된 데이터를 받기 위한 배열을 만든다
byte[] data = new byte[100];
try {
// 연결된 클라이언트와 계속 통신한다
// 혼자 대화, 여러명은 Thread 사용
while(true) {
is.read(data ); // 수신된 데이터를
os.write(data); // 그대로 클라이언트에게 보낸다
String msg = new String(data);
System.out.println("수신된 데이터 : " + msg);
Arrays.fill(data, (byte)0);
}
}catch(Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
}
public class TCPChatServerMulti {
public static void main(String[] args) {
try {
// 서버 소켓을 생성, 포트번호 9003
ServerSocket server = new ServerSocket(9005);
// 클라이언트의 접속을 무한대기상태로 기다린다
while(true) {
// 클라이언트에 접속을 수락
Socket socket = server.accept();
// 연결한 클라이언트와 계속 통신 할 쓰레드를 생성
ServerThread st = new ServerThread(socket);
// 쓰레드를 가동
st.start();
}
} catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
}
/여러명과 동시에 대화하기/
/연결된 클라이언트에게 메세지 보내기/
package com.kosta.chat03;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import javax.print.attribute.standard.Severity;
class ServerThread extends Thread {
Socket socket;
InputStream is;
OutputStream os;
// 나와 연결된 클라이언트에게 메세지를 보내는 메소드
public void send(byte[] arr) throws Exception {
os.write(arr);
}
// 연결된 모든 클라이언트들에게 메세지를 보내는 메소드
public void sendAll(byte[] arr) throws Exception {
for(ServerThread st : TCPChatServerBroadCast.list) {
st.send(arr);
}
}
public ServerThread(Socket socket){
// 데이터 입출력을 위한 스트림
try {
this.socket = socket;
is = socket.getInputStream();
os = socket.getOutputStream();
} catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
@Override
public void run() {
// 클라이언트로부터 수신된 데이터를 받기 위한 배열을 만든다
byte[] data = new byte[100];
try {
// 연결된 클라이언트와 계속 통신한다
// 혼자 대화, 여러명은 Thread 사용
while(true) {
is.read(data ); // 수신된 데이터를
// 연결된 모든 클라이언트들게에 보낸다
sendAll(data);
// os.write(data); // 그대로 클라이언트에게 보낸다
String msg = new String(data);
System.out.println("수신된 데이터 : " + msg);
Arrays.fill(data, (byte)0);
}
}catch(Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
}
public class TCPChatServerBroadCast {
// 연결된 클라이언트를 상대할 Server Thread의 리스트 선언
public static ArrayList<ServerThread> list;
public static void main(String[] args) {
// 리스트 생성
list = new ArrayList<ServerThread>();
try {
// 서버 소켓을 생성, 포트번호 9003
ServerSocket server = new ServerSocket(9003);
// 클라이언트의 접속을 무한대기상태로 기다린다
while(true) {
// 클라이언트에 접속을 수락
Socket socket = server.accept();
// 연결한 클라이언트와 계속 통신 할 쓰레드를 생성
ServerThread st = new ServerThread(socket);
// 쓰레드를 가동
st.start();
// 가동시킨걸 리스트에 담아준다
list.add(st);
}
} catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
}
package com.kosta.chat03;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Arrays;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class TCPChatClient extends JFrame {
// panel 1개, borderlayout, center/south
JTextArea jta;
JTextField jtf;
// Socket과 입출력을 위한 스트림을 멤버번수로 선언
Socket socket;
InputStream is;
OutputStream os;
public TCPChatClient() {
try {
// 1. 서버와 통신하기위한 소켓 생성(ip주소, port번호)
socket = new Socket("172.30.1.35", 9003);
// 2. 생성된 소켓을 통해 스트림 생성한다
is = socket.getInputStream();
os = socket.getOutputStream(); // 문자열을 byte 단위로 보낸다
jta = new JTextArea();
jtf = new JTextField(50);
JScrollPane jsp = new JScrollPane(jta);
JButton btnSend = new JButton("전송"); // 데이터를 보낸다
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
p.add(jtf, BorderLayout.CENTER);
p.add(btnSend, BorderLayout.EAST);
add(jsp, BorderLayout.CENTER);
add(p, BorderLayout.SOUTH);
setSize(300,200);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 서버로부터 수신된 데이터를 계속 받기위한 쓰레드
class ClientThread extends Thread{
byte[] data = new byte[100];
@Override
public void run() {
// 서버 데이터를 받아 텍스트 에리어에 출력
try {
while(true) {
is.read(data);
jta.append(new String(data));
jta.append("\n");
Arrays.fill(data, (byte)0);
}
}catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
}
ClientThread ct = new ClientThread();
ct.start(); // 쓰레드 가동
// 데이터를 보낼 전송 버튼의 이벤트
btnSend.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 보낼 데이터를 byte형의 배열로 갖고온다
// getBytes(); 텍스트에 써진걸 byte형으로 바꾼다
byte[] data = jtf.getText().getBytes();
try {
// 보내는 데이터 : os
os.write(data);
}catch (Exception ex) {
System.out.println("예외발생 : " + ex.getMessage());
}
jtf.setText(" ");
}
});
} catch (Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}
}
public static void main(String[] args) {
new TCPChatClient();
}
}
14:00 ~
download oracle XE 다운받기
데이터베이스(Datebase)
: 프로그램 실행한 결과를 화면에 출력하고
컴퓨터 전원을 끄면 그 내용은 사라지게 됩니다
실행결과를 영구적으로 저장하려면 "파일"에 기록할 수 있어요
그러나 "파일"은 다음과 같은 단점이 있어요
그 "파일"에 대한 이해관계에 있는 사람이 다수일때
최신의 정보를 공유하기가 어려워요
이해관계에있는 다수의 사람들이 항상 최신의 정보를 공유하기 위해서는
"데이터베이스"를 이용합니다
암호 : manager
DataBase : 데이터를 쌓아 놓은 더미
DataBase ManageMent System : DBMS
DBMS의 종류(?)
1) Oracle
2) MS sql
3) MySql <-- Oracle
4) MariaDB
Nosql
문서기반 NoSQL => MongoDB
- 오라클 접속 cmd > sqlplus
- 사용자 이름 system
- 사용자 암호 manager
- 프롬프트 sql > sql명령어 작성
- 오라클사용자 계정 만드는 데이터베이스 명령어
create user 사용자이름 identified by 암호;
- c##madang/ madang으로 만들기
create user c##madang identified by madang;
grant connect, resource, dba to c##madang;
- 연결 권한, 리소스 권한, dba 권한을 부여
grant connect, resource, dba to 사용자이름;
- 사용자 삭제
DROP USER [사용자명] CASCADE
- 테이블 만드는 명령어
create table 테이블이름 (속성명 자료형, 속성명 자료형..);
- 문자열 : varchar2(크기)
문자열 데이터는 ' '로 묶어줘야 한다
- 숫자 : number
- 테이블 구조
desc 테이블명
- 테이블에 자료 추가하는 명령어 (테이블 속성과 동일해야한다)
insert into 테이블명 values(값1, 값2 ..);
- 데이터 조회하는 명령어
select 속성1, 속성2, 속성3..;
select name from student;
- 모든 속성 보기
select * from student;
- 저장하기
commit;
** 사용자한테 이름, 국어, 영어, 수학을 입력받아 데이터베이스에 저장하는 프로그램을 작성
: 데이터베이스에 이러한 정보를 기록하기위한 "테이블"을 만들어야 해요
create table student(name varchar2(20), kor number, eng number, math number);
insert into student values('홍길동', 100, 100, 70);
<< JDBC 연결 프로그램 절차 >>
자바에서 데이터베이스에 연결하는 프로그램
Java DataBase Connect 프로그램 ==> JDBC
0. DBMS 드라이버를 오라클 설치된 경로에서 찾아 이클립스에 설정한다
프로젝트이름 오른쪽 클릭 > Properties > Libraries > Classpath > Add External JARs.. > Apply
1. DBMS 드라이버를 메모리로 로드한다
Class.forName("드라이브 이름");
Class.forName("oracle.jdbc.driver.OracleDriver");
2. DB서버에 연결한다
Connection conn = DriverManager.getConnection("DB서버의 url", "사용자이름", "사용자암호);
String url = "jdbc:oracle:thin:@localhost:1521:XE";
String username = "c##madang";
String password = "madang";
Connection conn = DriverManager.getConnection(url, username, password);
3. 데이터베이스 명령어 실행 담당자 객체를 생성한다
Statement stmt = conn.createStatement();
4. 실행담당자를 통해서 데이터베이스 명령어를 실행한다
int re = stmt.executeUpdate(sql); // int 반환
5. 사용했던 자원을 닫아준다
if(stmt != null){
stmt.colser();
}
if(conn != null){
conn.colser();
}
package com.kosta.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/*
자바에서 데이터베이스에 연결하는 프로그램
Java DataBase Connect 프로그램
==> JDBC
*/
public class InsertStudent {
public static void main(String[] args) {
String sql = "insert into student values('이순신', 80, 90, 100)";
Connection conn = null;
Statement stmt = null;
try {
// 1. JDBC 드라이버를 메모리로 로드한다
Class.forName("oracle.jdbc.driver.OracleDriver");
// 2. DB서버에 연결한다
String url = "jdbc:oracle:thin:@localhost:1521:XE";
String username = "c##madang";
String password = "madang";
conn = DriverManager.getConnection(url, username, password);
// 3. 데이터베이스 명령어 실행 담당자 객체를 생성
stmt = conn.createStatement();
// 4. 명령어 실행 담당자를 통해 데이터베이스 명령을 실행한다
int re = stmt.executeUpdate(sql);
if(re == 1) {
System.out.println("레코드 추가 성공");
}else {
System.out.println("실패");
}
}catch(Exception e) {
System.out.println("예외발생 : " + e.getMessage());
}finally {
try {
if(stmt != null) {
stmt.close();
}
if(conn!= null) {
conn.close();
}
}catch(Exception e){
}
}
}
}
- 오늘 학습한 내영에 대항 요약 및 정리하고 궁금한 점 질문합니다
- 요약 및 정리가 끝난 사람들은 다음을 프로그래밍 해 봅니다
1) 채팅 프로그램에서 닉네임을 입력하고 접속하도록 하고
메세지 전송시 닉네임#메세지 형태로 전송하도록 합니다
2) 사용자한테 이름, 국어, 영어, 수학을 입력받아 데이터베이스 테이블에 추가하도록
프로그래밍 해 봅니다 (CUI : Character User Interface, GUI : Graphical User Interface)
'📖' 카테고리의 다른 글
day 0607 데이터베이스 연결 프로그래밍 수정_삭제 (1) | 2024.06.07 |
---|---|
day 0605 데이터베이스 연결 프로그래밍 (0) | 2024.06.05 |
day 0603 메모장 (0) | 2024.06.03 |
day 0531 GUI 연습 (0) | 2024.05.31 |
day 0530 멀티쓰레드_임계영역_쓰레드사이의 통신 (0) | 2024.05.30 |