Socket multi-person Chat program C language version (i) _c language

Source: Internet
Author: User
Tags function prototype manage connection sleep strlen cpu usage server port htons

First of all, do not sweeping directly solve the problem of many people chat, first the problem of simplification.
1. The core issue of multiplayer chat is how the server identifies different clients, and how to forward messages to the specified client according to the needs of the client.
2. Many people chat into c-c chat, but no longer direct c-c, but through the server forwarding messages, so become ==>c-s-c.
3.server how to allow 2 client simultaneous connections, set the second parameter of the Listen function, the maximum number of connections.
4.server how to identify two client, use a structure array to store two client information.
5.server How to forward the message to the client, very simple, first received sent to have not received. As shown in figure:


6.server How to manage the two-client connection state, the success of the connection is very simple, that is, Accpet success is connected successfully. But how do you determine if the connection is disconnected? This involves the use of the Select function, a bit complicated ~, so I simply used a send function to send an empty message to determine whether the disconnect, this is not rigorous, easy to bug, but the practice is simple to use it.
7. Use threads to manage incoming messages, send messages, accept requests, and manage connection status.

Technical points: The use of C-language thread functions.

_beginthreadex function prototype

_acrtimp uintptr_t __cdecl _beginthreadex
(_in_opt_ void* security attribute, NULL as default security attribute
 _in_ unsigned the size of the _stacksize,//thread stack. If 0, the thread stack size is the same as the thread that created it. Generally with 0 
 _in_ _beginthreadex_proc_type _startaddress,//The address of the thread function
 _in_opt_ void* _arglist,//The function that is passed into the thread
 _in_ unsigned _initflag,//thread initial state, 0: Run immediately; Create_suspend: Hang (If an accident status is defined as hanging, call ResumeThread (HANDLE) to activate the running of the thread) 
 _out_opt _ unsigned* _thrdaddr//address for recording thread ID
 



Example:

#include <process.h>
#include <stdio.h>

unsigned __stdcall Thread (void* param)
{
  printf ("%d\n", * (int*) param); This must first be forcibly converted to int*, or void* direct dereference will be wrong. return
  0;
}

int main ()
{
  int i = 0;
  _beginthreadex (null, 0, Thread, &i, 0, null);
  return 0;
}


1v1,c-s-c Chat Example:
Authoring Environment: WIN10,VS2015

Effect Chart:

Server code:

#include <WinSock2.h> #include <process.h> #include <stdio.h> #include <stdlib.h> #pragma  Comment (lib, "Ws2_32.lib") #define SEND_OVER 1//Forwarded message #define SEND_YET 0//has not forwarded message int G_istatus
= Send_yet;   SOCKET g_serversocket = Invalid_socket;      Server socket sockaddr_in g_clientaddr = {0};
Client address int g_iclientaddrlen = sizeof (G_CLIENTADDR);        BOOL G_bcheckconnect = false;
Check the connection condition HANDLE g_hrecv1 = NULL;
HANDLE g_hrecv2 = NULL;   Client information structure typedef struct _CLIENT {SOCKET sclient;    Client socket char buf[128];  Data buffer char username[16];     Client username Char ip[20];    Client IP uint_ptr flag;

Mark the client to differentiate between different client}client;         Client G_client[2] = {0};
  Create a client structure//Send data thread unsigned __stdcall threadsend (void* param) {int ret = 0;
  int flag = * (int*) param;         SOCKET client = Invalid_socket;             Creates a temporary socket that holds the client socket char temp[128] = {0} to forward; Create a temporary data buffer to hold the received data memcpy (temp, g_client[!flag].buf,sizeof (temp)); sprintf (G_client[flag].buf, "%s:%s", G_client[!flag].username, temp);//Add a user name header if (strlen (temp)!= 0 && G_ist  ATUs = = Send_yet)///If data is not empty and forwarding is not forwarded ret = SEND (g_client[flag].sclient, G_client[flag].buf, sizeof (G_CLIENT[FLAG].BUF),
  0);
  if (ret = = Socket_error) return 1;  G_istatus = Send_over;
After the forwarding succeeds, the setting status is forwarded return 0;
  }//Accept data unsigned __stdcall threadrecv (void* param) {SOCKET client = Invalid_socket; 
  int flag = 0;
    if (* (int*) param = = G_client[0].flag)//Determine which client sent the message {clients = G_client[0].sclient;
  Flag = 0;
    else if (* (int*) param = = G_client[1].flag) {Client = g_client[1].sclient;
  flag = 1; } char temp[128] = {0};
    Temporary data buffer while (1) {memset (temp, 0, sizeof (temp)); int ret = recv (client, temp, sizeof (temp), 0);
    Receive data if (ret = = Socket_error) continue;                G_istatus = Send_yet; Set forwarding status to not forwarded flag = client = G_client[0].sclient?    1:0; This to be set, or it will appear to give itself toThe Bug memcpy (g_client[!flag].buf, temp, sizeof (G_CLIENT[!FLAG].BUF)) that sent the message itself; _beginthreadex (null, 0, threadsend, &flag, 0, NULL);
  Turn on a forwarding thread, flag marking which client to send to//This may also be the cause of the increase in CPU usage.
return 0; }//Admin connection unsigned __stdcall threadmanager (void* param) {while (1) {if (send G_client[0].sclient, "", sizeof ("") (0) = = socket_error) {if (g_client[0].sclient!= 0) {CloseHandle (G_HRECV1);//This closes the thread handle, but the test result is broken
        Open Connect C/s After the CPU still crazy up CloseHandle (G_HRECV2); printf ("Disconnect from IP:%s,username:%s\n", g_client[0).
        IP, G_client[0].username);  Closesocket (g_client[0].sclient);
      Here simple judgment: If send a message fails, the connection is considered to be interrupted (for a variety of reasons), close the socket g_client[0] = {0};
      } if (Send (G_client[1].sclient, "", sizeof (""), 0) = = socket_error) {if (g_client[1].sclient!= 0)
        {CloseHandle (G_HRECV1);
        CloseHandle (G_HRECV2); printf ("Disconnect from IP:%s,username:%s\n", g_client[1).
IP, G_client[1].username);        Closesocket (g_client[1].sclient);
      G_client[1] = {0}; } Sleep (2000);
2s check once} return 0;
  //Accept Request unsigned __stdcall threadaccept (void* param) {int i = 0;
  int temp1 = 0, temp2 = 0;
  _beginthreadex (null, 0, Threadmanager, NULL, 0, NULL);
        while (1) {while (I < 2) {if (g_client[i].flag!= 0) {++i;
      Continue //If a client requests a connection, accept the connection if (G_client[i].sclient = Accept (G_serversocket, (sockaddr*) &g_clientaddr, &AMP;G_ICL
        Ientaddrlen) = = Invalid_socket) {printf ("Accept failed with error code:%d\n", WSAGetLastError ());
        Closesocket (G_serversocket);
        WSACleanup ();
      return-1; } recv (G_client[i].sclient, G_client[i].username, sizeof (G_client[i].username), 0); Receive User name printf ("Successfuuly got a connection from ip:%s, Port:%d,uername:%s\n", Inet_ntoa (g_clientaddr.si
N_ADDR), htons (G_clientaddr.sin_port), g_client[i].username);      memcpy (G_client[i]. IP, Inet_ntoa (g_clientaddr.sin_addr), sizeof (g_client[i). IP)); Record client IP G_client[i].flag = g_client[i].sclient;
    Different Socke have different uint_ptr types of numbers to identify i++;

    } i = 0; if (g_client[0].flag!= 0 && g_client[1].flag!= 0)///When two users are connected to the server before message forwarding {if (g_client[0].fla G!= Temp1)////Every time you disconnect one connection will open a new thread, resulting in increased CPU usage, so to turn off the old {if (G_HRECV1)///here closed the thread handle, but the test results are disconnected from C/s after the CP
        U still Mad CloseHandle (G_HRECV1); G_HRECV1 = (HANDLE) _beginthreadex (null, 0, THREADRECV, &g_client[0].flag, 0, NULL); Open 2 threads that receive messages} if (G_client[1].flag!= temp2) {if (G_HRECV2) CloseHandle (G_HRECV2)
        ;
      G_hrecv2 = (HANDLE) _beginthreadex (null, 0, THREADRECV, &g_client[1].flag, 0, NULL); } Temp1 = G_client[0].flag;

    Prevent threadrecv threads from opening temp2 = G_client[1].flag;
  Sleep (3000);
return 0; //Start server int startserver () {//Hold socket information structure Wsadata WSAData = {0};       sockaddr_in serveraddr = {0};            Service-side address USHORT uport = 18000; Server listener port//Initialize socket if (WSAStartup (Makeword (2, 2), &wsadata)) {printf ("WSAStartup failed with error code:%
    D\n ", WSAGetLastError ());
  return-1; }//Judgement version if (Lobyte (wsadata.wversion)!= 2 | |
    Hibyte (wsadata.wversion)!= 2) {printf ("Wversion is not 2.2\n");
  return-1;
  ///Create Socket G_serversocket = socket (af_inet, sock_stream, ipproto_tcp);
    if (G_serversocket = = Invalid_socket) {printf ("SOCKET failed with error code:%d\n", WSAGetLastError ());
  return-1; //Set server address serveraddr.sin_family = af_inet;//Connection Mode serveraddr.sin_port = htons (uport);//server listening port Serveraddr.sin_ad Dr. S_un. S_ADDR = htonl (inaddr_any);//Any client can connect to this server//BIND server if (Socket_error = Bind (G_serversocket, sockaddr*) &serverad
    Dr, sizeof (SERVERADDR)) {printf ("Bind failed with error code:%d\n", WSAGetLastError ());
    Closesocket (G_serversocket); Return-1; //sets the Listener Client connection number if (Socket_error = = Listen (G_serversocket, 20000)) {printf (Listen failed with ERROR code:%d\n)
    , WSAGetLastError ());
    Closesocket (G_serversocket);
    WSACleanup ();
  return-1;
  } _beginthreadex (null, 0, threadaccept, NULL, 0, 0);
    for (int k = 0;k < 100;k++)//Let the main thread hibernate without it shutting down the TCP connection.

  Sleep (10000000); Closes the socket for (int j = 0;j < 2;j++) {if (g_client[j].sclient!= invalid_socket) closesocket (G_client[j].sc
  Lient);
  } closesocket (G_serversocket);
  WSACleanup ();
return 0;

 int main () {startserver ();//start server return 0;}

Client code:

#define _winsock_deprecated_no_warnings #include <WinSock2.h> #include <process.h> #include <stdio.h > #include <stdlib.h> #include <conio.h> #pragma comment (lib, "Ws2_32.lib") #define RECV_OVER 1 #define REC
V_yet 0 Char username[16] = {0};
int istatus = Recv_yet;
  Accept data unsigned __stdcall threadrecv (void* param) {char buf[128] = {0};
    while (1) {int ret = recv (* (socket*) param, buf, sizeof (BUF), 0);
      if (ret = = Socket_error) {sleep (500);
    Continue
      } if (strlen (BUF)!= 0) {printf ("%s\n", buf);
    Istatus = Recv_over;  


  else sleep (100);
return 0;
  }//Send data unsigned __stdcall threadsend (void* param) {char buf[128] = {0};
  int ret = 0;
    while (1) {int c = getch ();          if (c = = | | c = = 0 | | c = = 68)//To show beauty, add a no-echo read character function continue;
    Getch return value I was experimentally concluded that if the value is returned, then Getch will automatically skip, I do not understand.
    printf ("%s:", userName);
    gets_s (BUF); RET = Send (* (socket*) PARAM, buf, sizeof (BUF), 0);
  if (ret = = Socket_error) return 1;
return 0; }//connection server int ConnectServer () {wsadata wsadata = {0};//store socket information Socket Clientsocket = invalid_socket;//Client Socket SOC Kaddr_in serveraddr = {0};//service-side address USHORT uport = 18000;//Server port//Initialize socket if (WSAStartup (2, 2)
    &wsadata)) {printf ("WSAStartup failed with error code:%d\n", WSAGetLastError ());
  return-1; //Judge Socket version if (Lobyte (wsadata.wversion)!= 2 | |
    Hibyte (wsadata.wversion)!= 2) {printf ("Wversion is not 2.2\n");
  return-1;
  ///Create Socket Clientsocket = socket (af_inet, sock_stream, ipproto_tcp);
    if (Clientsocket = = Invalid_socket) {printf ("SOCKET failed with error code:%d\n", WSAGetLastError ());
  return-1;
  //Enter server IP printf ("Please input server IP:");
  Char ip[32] = {0};
  gets_s (IP);
  Set server address serveraddr.sin_family = af_inet; Serveraddr.sin_port = htons (uport);//server Port serveraddr.sin_addr. S_un. S_addr= Inet_addr (IP);//server address printf ("connecting......\n"); Connection server if (Socket_error = Connect (Clientsocket, (sockaddr*) &serveraddr, sizeof (SERVERADDR))) {printf ("Conne
    CT failed with error code:%d\n ", WSAGetLastError ());
    Closesocket (Clientsocket);
    WSACleanup ();
  return-1;
  printf ("Connecting Server successfully ip:%s port:%d\n", IP, Htons (Serveraddr.sin_port));
  printf ("Please input your UserName:");
  gets_s (UserName);
  Send (Clientsocket, userName, sizeof (UserName), 0);
  printf ("\ n \ nthe"); _beginthreadex (null, 0, THREADRECV, &clientsocket, 0, NULL);
  Start receiving and sending message threads _beginthreadex (NULL, 0, threadsend, &clientsocket, 0, NULL);
  for (int k = 0;k < 1000;k++) sleep (10000000);
  Closesocket (Clientsocket);
  WSACleanup ();
return 0;

 int main () {connectserver ();//connection server return 0;}

This program also has some bugs, the biggest is to turn off a connection after the CPU utilization rate is crazy, I tested the possibility of my thinking, or can not find the results ~, I hope to have the great God to understand the informed.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.