C++SOCKET 다 중 스 레 드 채 팅 애플 릿 구현

본 논문 의 사례 는 C+SOCKET 다 중 스 레 드 가 채 팅 애플 릿 을 실현 하 는 구체 적 인 코드 를 공유 하여 여러분 께 참고 하 시기 바 랍 니 다.구체 적 인 내용 은 다음 과 같 습 니 다.
TCP/IP 프로 토 콜 과 SOCKET
네트워크 프로 토 콜 이란 무엇 입 니까?
컴퓨터 네트워크 에서 각 실체 간 의 데이터 교환 은 반드시 사전에 약정 한 규칙 을 준수 해 야 하 는데 이런 규칙 을 협의 라 고 한다.
네트워크 프로 토 콜 의 구성 요 소 는 다음 과 같다.
1.문법,데이터 및 제어 정보의 구조 또는 형식
2.의미:어떤 통제 정 보 를 보 내 고 어떤 동작 을 완성 하 며 어떤 응답 을 해 야 하 는 지
3.순서:사건 실현 순서 에 대한 상세 한 설명
하나의 네트워크 프로 토 콜 에서 통신 의 실체의 같은 차원 의 구 조 는 반드시 같은 협 의 를 집행 해 야 한다.이것 은 협의의 대등한 원칙 이다.
TCP/IP 시스템 구조 및 SOCKET

TCP/IP 시스템 구조 에 대한 상세 한 내용 은 본 고 에서 논술 하지 않 습 니 다.이 분야 의 지식 이 없 으 면 이 를 신속하게 이해 하려 면 인터넷 통신 을 두 사람 사이 에 비교 하여 편 지 를 쓸 수 있 습 니 다.당신 의 편 지 는 통신 과정 에서 전달 해 야 할 메시지 나 데이터 입 니 다.인터넷 협 의 는 당신 의'편지'를 포장 하 였 습 니 다.예 를 들 어 우 표를 붙 이 고 봉 투 를 싸 서 메 일 박스 에 넣 은 후에 당신 의'편지'는 우체국 을 통 해 수신 자 에 게 보 낼 수 있 습 니 다.
SOCKET(소켓)은 TCP/IP 네트워크 운영 체제 가 네트워크 프로그램 개발 에 제공 하 는 전형 적 인 네트워크 프로 그래 밍 인터페이스 로 프로 세 스 는 SOCKET 을 통 해 메 시 지 를 보 내 고 메 시 지 를 받는다.SOCKET 을'문'으로 볼 수 있 습 니 다.메 시 지 를 보 내 는 프로 세 스 는'문'에서 메 시 지 를 내 보 낼 수 있 습 니 다.메시지 가 출시 된 후 하층 의 통신 시설 을 이용 하여 수신 프로 세 스 가 있 는'문'으로 전달 된다.그리고 프로 세 스 를 받 고'문'에서 메 시 지 를 끌 어 들 입 니 다.소켓 SOCKET 은 데이터 신문 소켓 과 스 트림 소켓 으로 나 뉘 어 각각 UDP 프로 토 콜 과 TCP 프로 토 콜 을 사용한다.
SOCKET 프로 그래 밍
저 희 는 단일 방송 채 팅 방 을 만 들 려 고 합 니 다.이 채 팅 방 은 여러 클 라 이언 트 와 서버 사 이 드 를 연결 할 수 있 습 니 다.단일 방송 은 각 클 라 이언 트 가 서버 와 만 단독 통신 할 수 있 고 서로 다른 클 라 이언 트 간 에 통신 할 수 없다 는 뜻 입 니 다.이 목 표를 실현 하기 위해 서 우 리 는 다 중 스 레 드 가 필요 하 다.전체적인 실현 방향 은 다음 과 같다.

말 이 많 지 않 으 니 코드 를 달 아 라.
서버 엔 드

#include "stdafx.h"
#include<WinSock2.h>
#include<string.h>
#include<iostream>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
const int PORT = 8000;
#define IP "127.0.0.1"
#define MaxClient 10//               ,      
#define MaxBufSize 1024
int num =0;//        
#define _CRT_SECURE_NO_WARINGS

//    
DWORD WINAPI SeverThread(LPVOID lpParameter)
{
    //    SOCKET    
 SOCKET *ClientSocket = (SOCKET*)lpParameter;
 int receByt = 0;
 char RecvBuf[MaxBufSize];
 char SendBuf[MaxBufSize];
 char exitBuf[5];
 //    
 while (1)
 {
  receByt = recv(*ClientSocket, RecvBuf, sizeof(RecvBuf), 0);
  if (receByt > 0)
  {
      //          “exit”,     
   if (strlen(RecvBuf)==4)
   {
    for (int i = 0; i < 5; i++)
    {
     exitBuf[i] = RecvBuf[i];
    }
    int flag = strcmp(exitBuf, "exit");
    if (flag==0)//   exit  
    {
     cout << "client " << *ClientSocket << " exit!" << endl;
     num--;
     send(*ClientSocket, "Your server has been closed", sizeof(SendBuf), 0);
     closesocket(*ClientSocket);
     return 0;
    }
   }
    cout << "receive message :" << RecvBuf << " from client:" << *ClientSocket << endl;
   
  }
  else
  {
      //                    
   if (WSAGetLastError() == 10054)//          
   {
    cout << "client " << *ClientSocket << " exit!" << endl;
    closesocket(*ClientSocket);
    num--;
    return 0;
   }
   else//          
   {
    cout << "failed to receive,Error:" << WSAGetLastError() << endl;
    break;
   }
   
  }
  memset(RecvBuf, 0, 1024);
  cout << "input your message to client:" << endl;
  scanf_s("%s",SendBuf,MaxBufSize);
  int k = 0;
  k = send(*ClientSocket, SendBuf, sizeof(SendBuf), 0);
  if (k < 0)
  {
   if (WSAGetLastError()==10054)//            
   {
    cout << "client " << *ClientSocket << " exit!" << endl;
    closesocket(*ClientSocket);
    num--;
    return 0;
   }
   else//          
   cout << "failed to send, Error:" << WSAGetLastError()<<endl;
  }
  memset(SendBuf, 0, 1024);
 }
 if (*ClientSocket != INVALID_SOCKET)
 {
  closesocket(*ClientSocket);
 }
 return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
 WSAData wsd;
 WSAStartup(MAKEWORD(2, 2), &wsd);
 SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, 0);
 SOCKADDR_IN ListenAddr;
 ListenAddr.sin_family = AF_INET;
 ListenAddr.sin_addr.S_un.S_addr = INADDR_ANY;//  ip
 ListenAddr.sin_port = htons(PORT);
 //      
 int n;
 n = bind(ListenSocket, (LPSOCKADDR)&ListenAddr, sizeof(ListenAddr));
 if (n == SOCKET_ERROR)
 {
  cout << "failed to bind!" << endl;
  return -1;
 }
 else
 {
  cout << "bind success to:" << PORT << endl;
 }
 //    
 int l = listen(ListenSocket, MaxClient);
 if (l == 0)
 {
  cout << "server ready, wait to requirement..." << endl;
 }
 else
 {
  cout << "Error:" << GetLastError() << "listen return" << l << endl;
 }
 while (1)
 {
  //                  
  if(num < MaxClient)
  {
   SOCKET *ClientSocket=new SOCKET;
   HANDLE hThread;
   int SockAddrlen = sizeof(sockaddr);
   *ClientSocket = accept(ListenSocket, 0, 0);
   cout << "client " << *ClientSocket << " has connect to server" << endl;
   num++;
   hThread = CreateThread(NULL, NULL, &SeverThread, (LPVOID)ClientSocket, 0, NULL);
   CloseHandle(hThread);
  }
  else
  {
   cout << "Max Client!Please wait for accept..." << endl;
  }
 }
 closesocket(ListenSocket);
 WSACleanup();
 return 0;
}
이 서버 에서 새로운 클 라 이언 트 가 연결 을 요청 할 때마다 서버 는 클 라 이언 트 에 게 서 비 스 를 제공 하 는 스 레 드 를 새로 열 고 이 스 레 드 에 SOCKET 을 새로 만들어 클 라 이언 트 와 통신 하 는 동시에 서버 도 서로 다른 단계(수신 또는 전송)에서 클 라 이언 트 가 연결 을 끊 었 는 지 확인 하여 자원 을 신속하게 방출 할 수 있어 야 합 니 다.
클 라 이언 트 엔 드

#include "stdafx.h"
#include<iostream>
#include<cstdio>
#include<string>
#include<Winsock2.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
const int PORT = 8000;
#define MaxBufSize 1024
#define _CRT_SECURE_NO_WARINGS

int _tmain(int argc, _TCHAR* argv[])
{
 WSADATA wsd;
 WSAStartup(MAKEWORD(2, 2), &wsd);
 SOCKET SocketClient = socket(AF_INET, SOCK_STREAM, 0);
 SOCKADDR_IN ClientAddr;
 ClientAddr.sin_family = AF_INET;
 ClientAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
 ClientAddr.sin_port = htons(PORT);
 int n = 0;
 n = connect(SocketClient, (struct sockaddr*)&ClientAddr, sizeof(ClientAddr));
 if (n == SOCKET_ERROR)
 {
  cout << "failed to connect" << endl;
  return -1;
 }
 cout << "success to connect to Server" << endl;
 
 char info[1024];//       
 char SendBuff[MaxBufSize];//       
 char RecvBuff[MaxBufSize];//       
 while (1)
 {
  cout << "input your message:" << endl;
  scanf_s("%s",&info,MaxBufSize);
  
  if (info[0] == '\0')
   break;
  strcpy(SendBuff, info);
  memset(info, 0, sizeof(info));
  int k = 0;
  k = send(SocketClient, SendBuff, sizeof(SendBuff), 0);
  memset(SendBuff, 0, sizeof(SendBuff));
  if (k < 0)
  {
   cout << WSAGetLastError() << endl;
   cout << "failed to send" << endl;
  }
  int n = 0;
  n = recv(SocketClient, RecvBuff, sizeof(RecvBuff), 0);
  if (n>0)
  {
   cout << "receive message from Server:" << RecvBuff << endl;
   memset(RecvBuff, 0, sizeof(RecvBuff));
  }
 }
 closesocket(SocketClient);
 WSACleanup();
 return 0;
}
이 예 에서 클 라 이언 트 와 서버 가 연결 되면 클 라 이언 트 가 먼저 메 시 지 를 보 내야 대 화 를 시작 할 수 있 습 니 다.중국어 와 영어 채 팅 을 지원 하고 한 번 에 최대 1024 바이트 의 데 이 터 를 보 냅 니 다.여러 개의 클 라 이언 트 를 만 들 려 면 몇 개의 프로젝트 를 새로 만 들 고 클 라 이언 트 의 코드 를 복사 해서 실행 하면 됩 니 다.컴 파일 된 exe 프로그램 을 직접 복사 하거나 복사 합 니 다.
총결산
이 예 에서 여러 클 라 이언 트 가 연결 을 만 들 었 을 때 그들 은 먼저 메 시 지 를 보 낼 수 있 습 니 다.서버 는 반드시 즉시 답장 을 하지 않 아 도 됩 니 다.서버 가 여러 클 라 이언 트 로부터 메 시 지 를 받 은 후에 답장 을 할 때 답장 의 순 서 는 수신 순서에 따라 오 는 것 입 니 다.누구의 소식 이 먼저 도착 하면 누 구 를 먼저 답장 합 니까?우 리 는 서버 에서 나의 다음 소식 을 누구 에 게 보 낼 지 지정 할 수 없다.이것 은 제 가 스 레 드 탱크 를 사용 하지 않 았 기 때문에 서로 다른 스 레 드 간 에 식별 할 수 없고 연결 을 만 들 수 없습니다.운영 체 제 는 기본적으로 여러 스 레 드 가 답장 을 기다 리 고 있 을 때(이때 이 스 레 드 는 연결 상태 에 있 습 니 다)특별한 규정 이 없고 자원 이 충분 하 다 면 선착순 을 따라 야 합 니 다.이 부분 을 철저히 이해 하려 면 운영 체제 에 관 한 지식 이 필요 하 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기