묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨Windows 소켓 프로그래밍 입문에서 고성능 서버까지!
송신 패킷 크기 관련해서 질문드립니다!
클라이언트에서 송신 관련해서 묶어서 보내는 코드를 설명하실 때 서버 코드에서도 이렇게 하는 게 좋다고 하셨는데 자세한 이유가 궁금합니다!MSS 한도에서 최대한 패킷의 크기를 크게 잡아야 NODELAY 옵션을 쓰지 않고도 패킷이 전송 지연을 최소화할 수 있어서 일까요~?
-
해결됨Slack 클론 코딩[백엔드 with NestJS + TypeORM]
socket io 미 연결 문제 (nest & flutter)
안녕하세요! socket관련한 서비스를 진행해보고 싶어서 제로초님의 강의를 들은 수강생입니다.현재 nest & flutter를 이용하고 있는데, flutter에서의 연결 및 다른 tool에서 socket io 연결이 되지 않으며 “외부 사이트로는 접근이 불가능한 오류”가 생겨서 조심스럽게 여쭤봅니다. 현재 로직은 채팅을 생성시, 채팅을 보여주는 리스트가 실시간으로 새로고침이 되는 부분을 작업중입니다.하지만, postman, httpie, hoppscotch의 부분에서 연결이 되지 않는 문제가 발생합니다.많은 방법을 찾아봤지만, 터미널에서 socket io cli를 통해서 로그는 볼 수 있지만, 다른 tool에서는 이용이 불가능한 방법에 대해서 알고 싶어서 질문드립니다!Socket io를 통해서 local, dev서버 연결 완료 하지만 postman의 socket io기능을 통해서 테스트를 진행하려고 할 때,postman으로 연결local에서는 문제가 없이 연길이 되지만, dev서버에서는 이러한 에러가 발생합니다. 또한 flutter 앱에서 연결을 하려면 다음과 같은 에러가 발생합니다.오류 메시지 "WebSocketException: Connection to 'http://~~~~.com:81/socket.io/?EIO=4&transport=websocket#' was not upgraded to websocket"는 클라이언트가 WebSocket 연결을 시도하였으나, 서버가 해당 연결을 WebSocket 프로토콜로 업그레이드하지 않았다는 것을 의미합니다. 이는 여러 가지 원인에 의해 발생할 수 있습니다: upgrade가 되지 않았다고 나와서 ,ngnix의 socket 부분에서 upgrade부분도 잘 넣어줬는데, 오류가 해결되지 않아서... 고민 끝에 질문 올립니다.Ngnix 설정부터 2주정도 시간을 들였지만, 해결이 되지 않아서…여쭤봅니다.방화벽도 해제가 되어 있는데 연결이 안되고 있습니다..다음은 nest에서 작성한 코드 입니다![chat.gateway.ts]import { WebSocketGateway, WebSocketServer, SubscribeMessage, OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit, ConnectedSocket, MessageBody, } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; @WebSocketGateway() export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect { @WebSocketServer() server: Server; afterInit(server: Server) { console.log('WebSocket initialized'); } handleConnection(client: Socket) { console.log(`Client connected: ${client.id}`); // 수정: client 객체 직접 출력 대신 id 출력 } handleDisconnect(client: Socket) { console.log(`Client disconnected: ${client.id}`); } @SubscribeMessage('sendMessage') handleMessage( @ConnectedSocket() client: Socket, @MessageBody() data: { message: string } ): void { console.log(`Received message from ${client.id}: ${data.message}`); this.server.emit('newMessage', data); // 모든 클라이언트에게 메시지 전송 console.log(`Received message: ${data.message}`); } } [main.ts]import { ConfigService } from '@nestjs/config'; import { NestFactory } from '@nestjs/core'; import { NestExpressApplication } from '@nestjs/platform-express'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { join } from 'path'; import { AppModule } from './app.module'; import { HttpExceptionFilter } from './common/exceptions/http-exception.filter'; import { SuccessInterceptor } from './common/interceptors/success.interceptor'; import { IoAdapter } from '@nestjs/platform-socket.io'; import { CustomIoAdapter } from './adapters/custom-io.adapter'; async function bootstrap() { const app = await NestFactory.create<NestExpressApplication>(AppModule); app.useWebSocketAdapter(new CustomIoAdapter(app)); const configService = app.get(ConfigService); const port = configService.get('server.port'); const mongoUrl = configService.get('DB.MONGO_URL'); console.log('MongoDB URL:', mongoUrl); app.enableCors({ origin: true, credentials: true, }); app.useStaticAssets(join(__dirname, '..', 'client'), { prefix: '/api/v1/client', }); app.useGlobalInterceptors(new SuccessInterceptor()); app.useGlobalFilters(new HttpExceptionFilter()); app.setGlobalPrefix('api/v1'); const swagger_options = new DocumentBuilder() .setTitle('Nyam-Docs') .setDescription('API description') .setVersion('2.0.1') .addApiKey( { type: 'apiKey', name: 'x-token', in: 'header', description: 'Enter token', }, 'x-token', ) .addApiKey( { type: 'apiKey', name: 'x-type', in: 'header', description: 'Enter type', }, 'x-type', ) .build(); const document = SwaggerModule.createDocument(app, swagger_options); SwaggerModule.setup('api-docs', app, document); await app.listen(port, '0.0.0.0'); console.log(`Application Listening on Port : ${port}`); } bootstrap();다음은 custom한 io입니다[custom.io.adpter.ts]import { IoAdapter } from '@nestjs/platform-socket.io'; import { INestApplication, Injectable } from '@nestjs/common'; import { ServerOptions } from 'socket.io'; @Injectable() export class CustomIoAdapter extends IoAdapter { constructor(app: INestApplication) { super(app); } createIOServer(port: number, options?: ServerOptions): any { const serverOptions: ServerOptions = { ...options, cors: { origin: '*', // 모든 도메인에서 접근 허용 methods: ['GET', 'POST', 'PUT', 'DELETE'], credentials: true }, transports: ['websocket', 'polling'], //pooling 없으면 연결 안 됨(socket) allowEIO3: true // Engine.IO 3.x 버전 클라이언트 허용 }; return super.createIOServer(port, serverOptions); } } 혹시 해결방법을 아시거나, 도움을 주실만한 정보가 있으시다면 알려주시면 정말 감사하겠습니다!
-
미해결모든 개발자를 위한 HTTP 웹 기본 지식
3way handshaking 시점의 패킷들의 정보
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]강의 너무 잘 듣고 있는데 궁금한 부분이 생겼어요..실제로 소켓 라이브러리를 통해서 TCP/IP에서 가상연결 ?의 느낌으로 3Way HandShaking이 일어난다고 말씀 하셨는데그렇다면 1. 구글 서버와 연결 하기 위해서 실제로 TCP/IP 계층의 패킷들이 만들어져야 하는데 거기서 세그먼트는 전송데이터(HTTP 메세지)는 빠지고 출발지, 목적지의 IP,PORT 들만 가지고 만들어져서 아래계층으로 헤더들을 추가해서서버랑 connetion 이 되는건가요 ?좀 더 부가적으로 설명하자면 전송데이터(HTTP 메세지)만 빠진 데이터들이 예를 들어 다시 밑으로 전송계층 -> 인터넷계층 -> 네트워크 계층으로 하나씩 감싸져서 상대 서버에 도착 후 3Way HandShaking 이후 connetion 이후 다시 소켓이나 혹은 애플리케이션 계층으로 돌아 전송데이터(HTTP 메세지)를 가지고 다시 차례대로 계층으로 헤더들이 다시 추가되어서 실제 데이터가 전송되는 지 너무 궁금해요.. (전 먼저 Connetion을 위해 HTTP메세지 없이 캡슐화 해서 보내고, Connetion 이후 다시 역캡슐화로 윗 계층가서 헤더 추가하고 다시 캡슐화 하고 보내는 걸로 이해했어요)그렇다면 가상연결의 느낌이랑 다른 거 같아서.. 가상연결은 TCP/IP에서 소켓 라이브러리를 통해 바로 연결되는 느낌인데 이론상 물리계층으로 데이터가 전달될텐데 이게 가능할 거 같진 않아서 헷갈려요 ㅠㅠ
-
해결됨외워서 끝내는 네트워크 핵심이론 - 기초
socket의 생성시점에 관하여
선생님! 안녕하세요.Server쪽 Socket의 생성 시점에 관하여 궁금한 점이 있습니다.질문)Server쪽 Socket은 무엇이 Trigger가 되어 Socket이 Create되고 Open되는지 궁금합니다.Client와 Server가 통신을 하기 위해선 우선 서로 Socket이 생성되어야 합니다.Client쪽에서 Process가 통신을 하기 위해 운영체제에게 요청하여 Socket을 생성(혹은 개방)한다는건 알겠습니다. 즉 Process의 요청이 Trigger가 되어 Socket이 생성이 되는거죠.그리고 Client에서 Socket이 만들어지면 Server로 요청이 가는데 이때 Server쪽 Socket이 Listen 즉 연결 대기 상태가 아니라면 Kernel의 TCP에서 연결을 받아줄 Socket이 없어서 응답을 못받아준다고 설명하셨습니다. 그럼 Server쪽에서는 Socket을 Create하고 Open되어 Listen 상태가 되어있어야 하는데 이는 무엇이 Trigger가 되어 만들어지는 건가요? 그니깐 Client에서 최초 요청을 보낼 때 Server는 이때 처음 Client에게서 요청이 온건데 그러면 당연히 Client와 통신할 사실을 모르고 있을거기 때문에 Process가 Socket을 생성해놓지 않았을거고 그러면 응답이 거부되는 상황밖에 안생기는데 이는 뭔가 아닌거 같아서요.Client에서 Server에 Socket을 만들어라는 뭔가 모르는 Trigger가 있는건가요? (나름 열심히 작성했는데 글 솜씨가 부족하여 제 질문의 의도를 파악하실지 모르겠습니다ㅠ)
-
미해결
socket.io 실행
안녕하세요채팅을 구현하기위해 socket.io를 썼는데 통신이 안되는 것같습니다 io에 주소를 제대로 넣었고 서버 on 마다 클라이언트에서 emit으로 작성했는데 작동하지 않습니다 이유가 무엇일까요? // server 파일의 코드입니다 require('dotenv').config(); const { createApp } = require('./app'); const { appDataSource } = require('./models/index'); const startServer = async () => { const app = createApp(); const PORT = process.env.PORT; await appDataSource .initialize() .then(() => { const server = app.listen(PORT, () => { console.log(`🟢server is listening on ${PORT}🟢`); }); const io = require('socket.io')(server, { cors: { origin: true, credentials: true, }, }); const { socketMessage } = require('./middlewares/socket.io'); socketMessage(io); }) .catch((err) => { console.log(`❌Failed server connect❌`); appDataSource.destroy(); }); }; startServer(); // server의 socket 파일의 코드입니다 const jwt = require('jsonwebtoken'); const chatDao = require('../models/chatDao'); const { catchAsync } = require('../utils/error'); const socketMessage = (io) => { io.use((socket, next) => { const token = socket.handshake.headers.authorization; if (!token) { return next(new Error('Authentication error')); } jwt.verify(token, process.env.SECRET_KEY, async (err, decoded) => { if (err) { return next(new Error('Authentication error')); } userId = decoded.userId; next(); }); }); io.on('connection', (socket) => { console.log('A User Connected.'); socket.on( 'create_room', catchAsync(async (postId, callback) => { const room = await chatDao.createRoom(userId, postId); socket.join(room.raw.insertId); callback(room.raw.insertId); }) ); socket.on( 'enter_room', catchAsync(async (roomId, callback) => { socket.join(roomId); callback(roomId); }) ); socket.on('new_text', async (content, roomId, callback) => { await chatDao.createChat(userId, content, roomId); socket.to(roomId).emit('new_text', content); callback(content); }); socket.on('disconnect', () => { console.log('접속이 해제되었습니다', socket.id); clearInterval(socket.interval); }); socket.on('error', (error) => { console.error(error); }); socket.on('send', (data) => { console.log(data); socket.emit('reply', { data, }); }); socket.interval = setInterval(() => { socket.emit('news', 'Hello Socket.IO'); }, process.env.SOCKET_INTERVAL || 1000); }); }; module.exports = { socketMessage }; // client 코드입니다import React, { useState, useContext } from 'react'; import io from 'socket.io-client'; import './chat.css'; import { MenuContext } from '../../components/Nav/MenuProvider'; const Token = localStorage.getItem('accessToken'); const socket = io.connect('http://192.168.0.194:4000', { withCredentials: true, extraHeaders: {Authorization: `Bearer ${Token}` } appDataSource.destroy(); }), }); socket.on('connection', () => { console.log('Connected to server'); }); const Chat = () => { const [roomId, setRoomId] = useState([]); const [searchData, setSearchData] = useContext(MenuContext); const handleCreateRoom = event => { event.preventDefault(); socket.emit('create_room', searchData, ({ searchData, roomId }) => { console.log(`Joined room ${roomId}`); setRoomId(roomId); }); }; const handleJoinRoom = roomId => { socket.emit('enter_room', roomId, roomId => { console.log(`Joined room ${roomId}`); setRoomId(roomId); }); }; const handleNewText = content => { socket.emit('new_text', content, roomId, content => { console.log(`Sent message: ${content}`); }); }; const handleNewText = content => { socket.emit('new_text', content, roomId, content => { console.log(`Sent message: ${content}`); }); }; const onCheckEnter = e => {if (e.key === 'Enter') { handleNewText(); } }; return ( <div className="h-screen pt-36"> <button onClick={handleCreateRoom}>테스트</button> <button onClick={() => handleJoinRoom(roomId)}>테스트2</button> <input id="input-text" type="text" onKeyDown={onCheckEnter} /> <button onClick={handleCreateRoom}>제출</button> </div> ); }; export default Chat;
-
미해결Slack 클론 코딩[실시간 채팅 with React]
렌더링 될 때마다 socket.io connect 오류
렌더링 될 때마다 socket.io가 connect이 되어 소켓상태에서 connect상태로 로그가 찍힙니다. 혹시 렌더링이 될때마다 socket .io connect를 시키지 않는 방법이 있을까요 ?
-
미해결따라하며 배우는 NestJS
socket관련 질문!
안녕하세요! 먼저 강의 잘 들었습니다 강의보고 따라해보니 CRUD 프로그램 개발에는 조금이나마 이해가 됩니다 그런데 socket을 이용하여 tcp 통신을 해야하는 프로젝트를 진행중인데 nest.js 공식 문서를 보니 @SubscribeMessage('event_name') 을 이용하여 데이터를 받고 emit을 이용하여 event_name으로 주는 환경이더라고요?? 현재 서버를 nest.js 기반으로 개발하고 개발해 놓은 클라이언트(c++작성)에서 tcp 통신을 하기 위해서는 c++ 클라이언트에서도 socket.io를 활용하여 event_name 을 통하여 통신을 해야하는 것인가요? 아니면 event_name 없이 단순 tcp 통신을 통해 binary 데이터를 주고 받을 수 있는 서버 nest.js 환경이 있을까요?? 제가 socket.io에 대해 이해한 내용이 맞는건지도 잘 모르겠지만 답변 부탁드리겠습니다!
-
미해결모든 개발자를 위한 HTTP 웹 기본 지식
3 handshake(with socket library) 관련 질문있습니다.
강의가 너무 유익해서 시간가는줄 모르고 잘 보고있습니다. 좋은 강의 만들어주셔서 대단히 감사합니다. 하지만 강의를 보다가 이해가 잘 안되는 부분이 있어서 질문 드립니다. 강의시간이 1:50 쯤의 그림을 보면서 "socket 라이브러리를 통해 전달" 한다는 것이 이해가 잘 되지 않았습니다. 이 말을 저는 socket 라이브러리가 알아서 3handshake를 해서 연결상태를 보장받고 이후 TCP/IP 패킷을 생성하고 http 메시지를 담아 보내는 것으로 이해했습니다. 그런데 이 과정 중 3handshake와 socket library에 모호한 점이 있었습니다. 1-1. socket 라이브러리에서 3 hand shake 를 그림에서의 과정과 다르게 별도로 진행하여 연결이 되었다고 판단되면, 패킷 생성하고 네트워크 인터페이스 레이어를 지나 인터넷을 통해 서버로 전달. 즉, http 통신 프로세스와는 별개로 따로 서버와 syn / syn+ack / ack 만 주고받는 통신진행을 진행하는지 1-2. 아니면 전체 프로세스(강의에서 제공한 그림처럼)를 http 메세지와 syn이 포함된 TCP/IP 패킷을 생성하여 3번(syn / syn+ack / ack) 진행하는지 만약 1-1번 처럼 socket 라이브러리에서 따로 서버측과 syn / syn+ack / ack 을 통신한다면, 2-1. 최초 서버로 http 요청시 socket 라이브러리에서 3handshake를 실패시 http 요청 자체가 보내지지 않는건지. 그렇게 되면 클라이언트는 어떠한 응답도 못받는 상태가 되는건가요? 2-2. socket 라이브러리에서 3handshake를 하는 과정도 동일하게 TCP/IP 패킷을 생성하는지, 단순히 syn / syn+ack / ack 만 보내는지 궁금합니다. 3-1. 마지막으로 궁금한 것은 socket 라이브러리가 이런 것을 담당한다면 TCP를 이용한다면 반드시 socket 라이브러리를 써야하는 건지 궁금합니다. socket 라이브러리도 대체 가능한지 궁금합니다.
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Connector.Connect 질문입니다.
클라에서 Connector를 통해서 연결시도를 할 때, Connector에게 endPoint를 전달합니다 Connector에서는 socket에 endPoint.AddressFamily를 전달하는데, 제가 생각하는 것은 IP주소 '만' 전달합니다. 뒤에 SocketAsyncEventArgs args 변수를 선언하고 args.RemoteEndPoint에 endPoint를 한 번 더 전달합니다. socket.ConnectAsync할 때 args를 전달합니다. 헷갈리는 부분은 endPoint를 두번 전달하는 것입니다. socket에는 IP주소'만' 들어있어서 포트번호를 모르니 args.RemoteEndPoint에 port번호 포함 주소를 다시 준 것 인가요?
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Listener에서 새로운 Session을 생성할때마다 각자 다른 Socket이 할당되는 원리
클라이언트가 접속했을때 Listener에서 session.Start(args.AcceptSocket); 을 통해 Session에 Socket을 주입하는데, new 하는곳이 없는데 어떻게 Socket을 자동으로 생성해서 AcceptSocket에 할당해서 뿌려주는지 알고싶습니다. Listen 함수가 호출된 소켓만이 AcceptAsync에서 응답이 왔을때 초기화 해주는 것일까요? 그리고 args.AcceptSocket = null; 로 밀어주는 이유가 있을까요? 다른건 다 초기화 되는데 이것만 초기화되지 않는 이유가 따로 있을까요?
-
미해결모든 개발자를 위한 HTTP 웹 기본 지식
http통신을 socket 통신이라고 할 수 있나요?
영한님 강의를 통해서 열심히 웹공부 중인 학생입니다. 늘 감사하게 강의를 듣고 있습니다! '웹 브라우저 요청흐름' 강의를 통해서, 실시간 기술이 필요한 게임같은 경우를 제외하고 일반적인 요청-응답 방식으로 http통신을 이용한다는 것을 알 수 있었습니다. http 통신 과정에서 os에 내장되어있는 socket 라이브러리를 통해 TCP/IP 프로토콜로 서버와 커넥션(3-way handshaking)하게끔 한다고 하셨는데, 이 부분에서 클라이언트가 TCP 프로토콜을 직접 사용하지 않고, socket 라이브러리가 대행해준 것 (= 간접적으로 사용)이라고 이해하였습니다. 제가 여쭤보고 싶은건, 보통 http 통신과 실시간 socket 통신으로 구분 짓는 경우가 있는데, http 통신도 socket 라이브러리를 이용한다면 큰 범주로 소켓을 사용한 socket 통신이라고 말할 수 있는 것인가요? 그렇게 된다면 socket 통신이 TCP 프로토콜을 직접 사용하는 것이니, http 통신이 TCP 프로토콜을 간접적으로 사용한다는 부분이 이해가 되지 않습니다..! http통신의"소켓" 라이브러리와 실시간 "소켓"통신에서의 소켓이 다른 맥락인것인지.. 감사합니다!