Socket console dual-thread chat program
Today, I finally won the simplest socket (TCP mode) + thread chat program. Hey hey, I still remember the embarrassing situation when I wrote this program a few days ago. Now I am very angry.
For the general socket programming example, it is difficult to explain how to use a socket to send a piece of information. When watching Sun Xin's video, I wanted to write my own chat program. The function was to chat and send files.
Later, we found that to receive information while sending information, we had to have another thread outside the main thread to help.
After several days of study (in fact, classes, games, etc. are required every day ...), Our family also had a little bit of cake. In one breath, we had to deal with this simple chat program. Function: only chat, single chat, disconnection, and restart. Haha.
A slightly distinctive feature is the processing of strings, which makes the chat look a bit interface effect.
Well, let's talk about the specific implementation of the program.
The client code is as follows:
# Pragma comment (Lib, "ws2_32.lib ")
# Include <winsock2.h>
# Include <iostream>
# Include <string>
Using namespace STD;
Int follow = 0;
String show = "";
Void recvproc (socket sockconnect)
{
Char msgrcv [100] = {0 };
While (true)
{
If (socket_error = Recv (sockconnect, msgrcv, sizeof (msgrcv), 0 ))
{
Cout <"/n the other party has gone offline ";
Return;
}
If (msgrcv [0]! = '/0 ')
{
Show. Erase (show. End ()-7, show. End ());
Show + = "the other party said :";
Show + = msgrcv;
Show + = '/N ';
Show + = "input :";
System ("CLS ");
Cout <show;
}
}
}
Int main (INT argc, char * argv [])
{
// Load socket and its version
Word wversionrequested;
Wsadata;
Int err;
Wversionrequested = makeword (1, 1); // makeword macro
Err = wsastartup (wversionrequested, & wsadata );
If (Err! = 0 ){
Return 1;
}
If (lobyte (wsadata. wversion )! = 1 |
Hibyte (wsadata. wversion )! = 1 ){
Wsacleanup (); // low (main) and high (Deputy)
Return 1;
}
// Create a socket and set it
Socket socksrv = socket (af_inet, sock_stream, ipproto_tcp );
Sockaddr_in addrsrv;
Memset (& addrsrv, 0, sizeof (addrsrv ));
Addrsrv. sin_addr.s_un.s_addr = htonl (inaddr_any );
Addrsrv. sin_family = af_inet;
Addrsrv. sin_port = htons (6000 );
// Bind
If (BIND (socksrv, (sockaddr *) & addrsrv, sizeof (sockaddr) = socket_error)
{
Cout <"BIND error" <Endl;
}
// Listen
If (Listen (socksrv, 5) = socket_error)
{
Cout <"Listen error" <Endl;
}
// Accept
Sockaddr_in addrclient;
Int Len = sizeof (sockaddr); // caution: Len shocould be initial as sizeof (sockaddr ),
// Or accepting will be failed
While (true)
{
Cout <"Wait for the customer to establish a connection ...";
Socket sockconnect = accept (socksrv, (sockaddr *) & addrclient, & Len );
If (sockconnect = invalid_socket)
{
Cout <"invalid socket" <Endl;
Return 0;
}
// Recv thread
Createthread (null, 0,
(Lpthread_start_routine) recvproc, (void *) sockconnect,
0, null );
// Send
While (true)
{
Char Buf [100] = {0 };
Show + = "input :";
System ("CLS ");
Cout <show;
Cin> Buf;
Show. Erase (show. End ()-7, show. End ());
Show + = "I said :";
Show + = Buf;
Show + = '/N ';
Send (sockconnect, Buf, sizeof (BUF), 0 );
}
Closesocket (sockconnect );
}
// End Winsock DLL
Wsacleanup ();
Return 0;
}
If you have already started to learn socket programming, you can jump to
While (true)
{
Cout <"Wait for the customer to establish a connection ...";
......
And I will not talk about it.
After the accept function returns a new socket, the process starts to communicate, because the sending and receiving operations need to be separated, and a main thread should be created, therefore, we only need to create another thread. This thread can be send or Recv. Here I select Recv, and the main thread is responsible for sending information.
Note that the recvproc parameter (the only one) is socket, and this socket is returned by the accept function just now. In this way, the relationship with the main thread is established. (This socket is like a handle that provides access)
Recvproc does its own work and receives information. Because it is in the blocking mode, even the while loop does not consume CPU resources. In the blocking mode, the Recv will not be allowed to run until there is information. Otherwise, it will be blocked and hung.
The while loop in the main thread does not waste CPU resources. Cin is the same as Recv, waiting for user input.
So what is the running situation (Interface?
It can be understood that the main thread and sub-thread use the I/O device to output information, so that everyone can output their own things without interference. However, this is prone to disorder. The output of the main thread will be output by the thread at once, and the input of the main thread will be required. I thought a few ways to prevent disorder, but it was not ideal. I finally thought of using a String object of the standard library to save all the information on the interface. Hey hey, this looks good. Let's take a look at the changes in the show of the string object. There are two places: Recv, send, and so on.
The client only sends the code at the end.
One problem is that the string object show is too large. I think if the number of show '/N' reaches the number of lines on the console interface, if the string is added, save the remaining parts to the file and delete them from show.
Of course, there are still many problems with the program, such as not releasing sub-thread resources, etc...
Appendix: client source code:
# Pragma comment (Lib, "ws2_32.lib ")
# Include <winsock2.h>
# Include <iostream>
# Include <string>
Using namespace STD;
// Client CPP
String show = "";
Void recvproc (socket sockclient)
{
Char msgrcv [100] = {0 };
While (true)
{
If (socket_error = Recv (sockclient, msgrcv, sizeof (msgrcv), 0 ))
{
Cout <"/n the other party has gone offline ";
Return;
}
If (msgrcv [0]! = '/0 ')
{
Show. Erase (show. End ()-7, show. End ());
Show + = "the other party said :";
Show + = msgrcv;
Show + = '/N ';
Show + = "input :";
System ("CLS ");
Cout <show;
}
}
}
Int main (INT argc, char * argv [])
{
// Load socket and its version
Word wversionrequested;
Wsadata;
Int err;
Wversionrequested = makeword (1, 1); // makeword macro
Err = wsastartup (wversionrequested, & wsadata );
If (Err! = 0 ){
Return 1;
}
If (lobyte (wsadata. wversion )! = 1 |
Hibyte (wsadata. wversion )! = 1 ){
Wsacleanup (); // low (main) and high (Deputy)
Return 1;
}
// Create a client socket
Socket sockclient = socket (af_inet, sock_stream, ipproto_tcp );
// Set the address of the server
Sockaddr_in addrsrv;
Addrsrv. sin_addr.s_un.s_addr = inet_addr ("192.168.1.100 ");
Addrsrv. sin_family = af_inet;
Addrsrv. sin_port = htons (6000 );
// Connect
Connect (sockclient, (sockaddr *) & addrsrv, sizeof (sockaddr ));
// Recieve MSG thread
Createthread (null, 0,
(Lpthread_start_routine) recvproc, (void *) sockclient,
0, null );
// Send msg
While (true)
{
Char Buf [100] = {0 };
Show + = "input :";
System ("CLS ");
Cout <show;
Cin> Buf;
Show. Erase (show. End ()-7, show. End ());
Show + = "I said :";
Show + = Buf;
Show + = '/N ';
Send (sockclient, Buf, sizeof (BUF), 0 );
}
// Close socket to release the resource
Closesocket (sockclient );
Wsacleanup ();
Return 0;
}