Socket multi-person Chat program C language version (i) Address: http://www.jb51.net/article/94938.htm
The 1v1 is realized, and the 1V is much easier. However, relative to the 1V1 program, I have undergone a major change, the use of linked lists to dynamic management. This efficiency is really improved a lot, at least the CPU utilization rate is stable below 20, will not soar to 100. In C language to write this is still very time-consuming, because of what function to write their own, unlike C + + have STL library can be used, MFC write more simple, and then I will update the MFC version of the multiplayer chat program. Okay, cut the crap, get into the subject.
The issues to be addressed by this program are as follows:
1.CPU use rate soaring problem –> dynamic management of linked list
2. User-defined chat, just want to talk to who and who to talk –> _ Theclient structure adds a Chatname field that represents who you want to chat with, and this field is important because the server forwards the message by following this field.
3. Halfway to chat, is chatting, want to talk with others, and they also can receive other people sent messages –> This will be small change the client code, you can send chat message before inserting a piece of code, used to switch chat users. The practice is to read the ESC key with the Getch () function, if the user presses this key, indicates that they want to switch the user, and then output a line of prompts, please enter chat name, which is the name you want to chat with, send the name to the past to add an identifier, indicating that this message is to switch chat user messages. When the server receives this message and then determines whether the first character is an identifier and the second character cannot be an identifier, it finds the current online user based on this name, and then modifies the user who wants to switch the chat user chatname to name. (may be a bit around, do not understand the code can be clearly understood ~)
4. After the line to remind each other –> or the old routine, as long as send each other not pass when the other side of the line.
Authoring Environment: WIN10,VS2015
Effect Chart:
In order to facilitate the use of virtual machine demo, but in the virtual machine is certainly possible, it should be said as long as the LAN, can ping each other can be used this program.
Server Code:
Linked list header file:
#ifndef _client_link_list_h_ #define _client_link_list_h_ #include <WinSock2.h> #include <stdio.h>//client Information The structure typedef struct _CLIENT {SOCKET sclient; Client socket char buf[128]; Data buffer char username[16]; Client username Char ip[20]; Client IP unsigned short Port; Client port UINT_PTR Flag; Tag client, used to differentiate between different client char chatname[16]; Specify which client you want to chat with _client* next;
Points to the next node}client, *pclient;
* * Function initialization linked list * Return no returns value */void Init ();
* * Function Fetch head node * return head node/pclient getheadnode ();
* * Function to add a client * param client indicates that there is no return value/void Addclient (Pclient clients) for an object *
/* Function Deletes a client * param flag identifies a client object * Return True indicates a successful deletion, false indicates failure/BOOL Removeclient (UINT_PTR flag); /* Function According to name lookup specifies client * param name is the user name of the specified client * return returns a clients to indicate a successful lookup, return Invalid_socket to indicate no this user/SOCKET findclient (c
har* name); * * Function According to the socket to find the specified client * param client is a socket for the specified clients * return returns a pclient to indicate a successful lookup, return null means no this user/pclient findclient (Socke
T client);
* * Function COMPUTE Client Connection * param client represents a client object * return number of connections/int countcon ();
* * Function Empty list * Return no returns value */void clearclient ();
/* Function checks connection status and closes a connection * return value/void Checkconnection (); * * function specifies which client to send * param fromname, sender * param toname, recipient * param data, message sent/void SendData (char* fromname, Cha
r* ToName, char* data);
#endif//_client_link_list_h_
Linked List CPP file:
#include "ClientLinkList.h" pclient head = (pclient) malloc (sizeof (_client));
Create a head node/* Function Initialization list * Return no value/void Init () {head->next = NULL;}
* * Function Fetch head node * return header node/pclient Getheadnode () {returns head;} * * Function to add a client * param client indicates that there is no return value/void Addclient (Pclient client) {Client->next = HEAD-&G T;next; For example: head->1->2, then add a 3 come in head->next = client; 3->1->2,HEAD->3->1->2}/* Function deletes a client * param flag identifies a client object * Return True indicates deletion success, false indicates failure/b Ool removeclient (uint_ptr flag) {//Traverse, compare pclient pcur = Head->next;//pcur point to the first node pclient ppre = head; Ppre point to Head while (pcur) {//head->1->2->3->4, to delete 2, direct 1->3 if (Pcur->flag = flag) {Ppre
->next = pcur->next; Closesocket (pcur->sclient); Turn off socket free (pcur);
Release the node return true;
} ppre = Pcur;
Pcur = pcur->next;
return false; }/* Function lookup specified client * param namE is the user name of the specified client * return returns the SOCKET to indicate a successful lookup, return invalid_socket means no this user/socket Findclient (char* name) {///from the beginning traversal, compare Pclient pcur
= head;
while (Pcur = Pcur->next) {if (strcmp (pcur->username, name) = = 0) return pcur->sclient;
return invalid_socket; } * * Function according to the socket lookup client * param client is the specified client socket * Return returns a pclient to indicate a successful lookup, return null means no this user/pclient findclient (so
Cket client) {//From the beginning traversal, a comparison pclient pcur = head;
while (Pcur = Pcur->next) {if (pcur->sclient = client) return pcur;
return NULL;
}/* * Function COMPUTE Client Connection number * Param client represents a Clients object * Return returns the number of connections/int Countcon () {int icount = 0;
Pclient pcur = head;
while (pcur = Pcur->next) icount++;
Return icount;
}/* Function empty list * Return no returns value/void Clearclient () {pclient pcur = head->next;
Pclient ppre = head;
while (pcur) {//head->1->2->3->4, delete the 1,head->2 first, then free 1 pclient p = pcur;
Ppre->next = p->next;
Free (p);
Pcur = ppre->next; }
}
/* * function checks the connection state and closes a connection * return value/void Checkconnection () {pclient pclient = Getheadnode (); while (pclient = Pclient->next) {if (Send (Pclient->sclient, "", sizeof (""), 0) = = socket_error) {if (Pclie
Nt->sclient!= 0) {printf ("Disconnect from IP:%s,username:%s\n", Pclient->ip, Pclient->username); Char error[128] = {0};
Send the offline message to the person who sent the message sprintf (Error, "The%s was downline.\n", pclient->username);
Send (Findclient (pclient->chatname), error, sizeof (error), 0); Closesocket (pclient->sclient);
Here is a simple judgment: if sending a message fails, the connection is considered to be interrupted (for many reasons), and the socket Removeclient (Pclient->flag) is closed;
Break }}/* * function specifies which client to send * param fromname, sender * param toname, recipient * param data, message sent/void SendData (char* F
Romname, char* toname, char* data) {SOCKET client = findclient (toname);//Find out if there is this user char error[128] = {0};
int ret = 0;
if (client!= invalid_socket && strlen (data)!= 0) {char buf[128] = {0}; sprintf (BUF, "%s:%s ", fromname, data);
Add user name to send message ret = Send (client, buf, sizeof (BUF), 0);
else//send the error message to the person who sent the message {if (client = invalid_socket) sprintf (Error, "The%s was downline.\n", toname);
else sprintf (Error, "Send to%s" Allow empty, please try again!\n ", toname);
Send (Findclient (fromname), error, sizeof (error), 0);
if (ret = = socket_error)//Send the offline message to the person who sent the message {sprintf (ERROR, "the%s was downline.\n", toname);
Send (Findclient (fromname), error, sizeof (error), 0);
}
}
Server CPP:
/* #include <WinSock2.h> #include <process.h> #include <stdlib.h> #include "ClientLinkList.h" #pragma Comment (lib, "Ws2_32.lib") SOCKET g_serversocket = Invalid_socket; Server socket sockaddr_in g_clientaddr = {0};
Client address int g_iclientaddrlen = sizeof (G_CLIENTADDR);
typedef struct _SEND {char fromname[16];
Char toname[16];
Char data[128];
}send,*psend; Send data thread unsigned __stdcall threadsend (void* param) {psend psend = (psend) param;//convert to send type SendData (Psend->fromnam E, Psend->toname, psend->data);
Send data return 0;
}//Accept data unsigned __stdcall threadrecv (void* param) {int ret = 0;
while (1) {pclient pclient = (pclient) param;
if (!pclient) return 1;
ret = recv (pclient->sclient, Pclient->buf, sizeof (PCLIENT->BUF), 0);
if (ret = = Socket_error) return 1; if (pclient->buf[0] = = ' # ' && pclient->buf[1]!= ' # ')//#表示用户要指定另一个用户进行聊天 {Socket socket = findclient ( &PCLIENT->BUF[1]); Verify if the customer exists IF (Socket!= Invalid_socket) {pclient c = (pclient) malloc (sizeof (_client)); c = findclient (socket);
Whenever the chatname is changed, the message is automatically sent to the specified user memset (pclient->chatname, 0, sizeof (pclient->chatname));
memcpy (Pclient->chatname, c->username,sizeof (pclient->chatname));
else Send (pclient->sclient, "the user have not online or not exits.", 64,0);
Continue
} psend psend = (psend) malloc (sizeof (_send)); Assigns the sender's username and the user and message receiving the message to the struct, and then passes it as a parameter into the Send message process memcpy (psend->fromname, Pclient->username, sizeof (psend->
FromName));
memcpy (Psend->toname, Pclient->chatname, sizeof (psend->toname));
memcpy (Psend->data, Pclient->buf, sizeof (Psend->data));
_beginthreadex (null, 0, threadsend, psend, 0, NULL);
Sleep (200);
return 0;
//Open Receive message thread void Startrecv () {pclient pclient = Getheadnode ();
while (pclient = pclient->next) _beginthreadex (null, 0, THREADRECV, pclient, 0, NULL); }//Admin connection unsigned __stdcall ThReadmanager (void* param) {while (1) {checkconnection ();//Check Connection Status Sleep (2000);
2s check once} return 0;
//Accept Request unsigned __stdcall threadaccept (void* param) {_beginthreadex (null, 0, Threadmanager, NULL, 0, NULL); Init ();
Initialization must not be done while inside, otherwise the head will always be null!!!
while (1) {///Create a new client object pclient pclient = (pclient) malloc (sizeof (_client)); If a client requests a connection, it accepts the connection if (Pclient->sclient = Accept (G_serversocket, (sockaddr*) &g_clientaddr, &g_
Iclientaddrlen) = = Invalid_socket) {printf ("Accept failed with error code:%d\n", WSAGetLastError ());
Closesocket (G_serversocket);
WSACleanup ();
return-1; } recv (Pclient->sclient, Pclient->username, sizeof (Pclient->username), 0);
Username recv (pclient->sclient, Pclient->chatname, sizeof (Pclient->chatname), 0) receiving user name and specified Chat object; memcpy (Pclient->ip, Inet_ntoa (g_clientaddr.sin_addr), sizeof (PCLIENT->IP)); Log client IP Pclient->flag = pclient->sclient; Different Socke have different uint_ptr types of numbers to identify PCLIEnt->port = htons (G_clientaddr.sin_port); Addclient (pclient); Add new clients to printf in the list ("Successfuuly got a connection from ip:%s, Port:%d,uername:%s, Chatname:%s\n", pclient->
IP, Pclient->port, pclient->username,pclient->chatname);
if (Countcon () >= 2)///When at least two users are connected to the server before message forwarding startrecv ();
Sleep (2000);
return 0;
//Start server int startserver () {//Store 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_addr. S_un. S_ADDR = htonl (inaddr_any);//Any client can connect to this server//BIND server if (Socket_error = Bind (G_serversocket, sockaddr*) &serveradd
R, 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), WSA
GetLastError ());
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);
Close socket clearclient ();
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};
Char chatname[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 =)//esc ASCII is {memset (buf, 0, sizeof (BUF));
printf ("Please input the chat name:");
gets_s (BUF);
Char b[17] = {0};
sprintf (b, "#%s", buf);
RET = Send (* (socket*) param,b, sizeof (b), 0); if (ret = = Socket_error) return 1;
Continue } 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 sock
Addr_in serveraddr = {0};//service-side address USHORT uport = 18000;//Server port//Initialize socket if (WSAStartup (2, 2), Makeword)
{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; }//Input serviceIP 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 ("Connect f
Ailed 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 ("Please input the Chatname:");
gets_s (Chatname);
Send (Clientsocket, chatname, sizeof (Chatname), 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;}
Finally, the following points need to be improved:
1. No message records, so it is best to use documents or database records, personal referral database.
2. No user registration, landing operations, but also with the file or database to get. Read the database information as soon as the program is running.
3. Group chat function did not get, this is actually very simple, that is, the server regardless of 3721, the received message forwarded to all online users.
4. There is no offline message, this will use the database to store offline messages, and then immediately after the user sent to the past on the line.
Finally summed up, there is no database chat program is very simple ~,c language written procedures to pay attention to the operation of memory. There is also the TCP way of the connection too time-consuming memory (when the user amounts to).
C language version of the chat program (TCP version, followed by the UDP version) here to end ~, you are welcome to put forward their views.
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.