Recently learn Linux socket programming, see UNP that book, by the Way wrote a similar to the simplest chat function software, the interface is written with Qt, write down summed up it, if there is a problem, you are welcome to communicate with me.
The mode is C/s mode, the server waits for the request, and the client sends the request. The connection is TCP not UDP, but the UDP implementation is simpler.
I. The environment builds
I use Docker to build a few virtual machines, concrete construction way can refer to the online or I wrote before Docker summary: Click to open the link
Docker is still very lightweight, much faster than a typical virtual machine.
After building a good Docker is the basic first to see whether the network Unicom, if not connected to see links, firewall settings.
Two. No interface code implementation:
This part of the code mainly refer to the simple example on the UNP, which will certainly have bugs, because the complex TCP environment is not considered, but simply to implement the first:
Server side:
#include "unp.h" #include <stdio.h> #include <unistd.h> void Answer (file *fop, file *fip, int sockfd) {i
NT MAXFDP1, stdineof;
Fd_set RSet;
Char Buf[maxline];
int n;
stdineof = 0;
Fd_zero (&rset); for (;;)
{if (stdineof = = 0) fd_set (Fileno (FIP), &rset);
Fd_set (SOCKFD, &rset);
MAXFDP1 = Max (Fileno (FIP), SOCKFD) + 1;
Select (MAXFDP1, &rset, NULL, NULL, NULL);
if (Fd_isset (SOCKFD, &rset)) {* * * * * * is readable/if ((n = Read (SOCKFD, buf, maxline)) = = 0) { if (stdineof = = 1) return;
/* Normal termination */else Err_quit ("Client quit!");
Write (Fileno (FOP), buf, N); } if (Fileno (FIP), &rset) {/* input is readable/if (n = Read (Fileno (FIP), buf, M axline)) = = 0) {Stdineof = 1; Shutdown (SOCKFD, SHUT_WR);
/* Send FIN/FD_CLR (Fileno (FIP), &rset);
Continue
} writen (SOCKFD, buf, N);
int main (int argc, char **argv) {int listenfd, CONNFD;
pid_t Childpid;
Socklen_t Clilen;
struct sockaddr_in cliaddr, servaddr;
LISTENFD = Socket (af_inet, sock_stream, 0);
Bzero (&servaddr, sizeof (SERVADDR));
servaddr.sin_family = af_inet;
SERVADDR.SIN_ADDR.S_ADDR = htonl (Inaddr_any);
Servaddr.sin_port = htons (Serv_port);
Servaddr.sin_port = htons (50001);
Bind (LISTENFD, (SA *) &servaddr, sizeof (SERVADDR));
Listen (LISTENFD, Listenq); for (;;)
{Clilen = sizeof (CLIADDR);
if ((CONNFD = Accept (LISTENFD, (SA *) &cliaddr, &clilen)) < 0) {if (errno = = eintr) Continue
/* Back to for () */ else Err_sys ("Accept error"); } if ((Childpid = Fork ()) = = 0) {/* child process/close (LISTENFD);
/* Close Listening socket * * Answer (stdout, stdin, CONNFD);
printf ("End of one connect!\n");
Exit (0); Close (CONNFD); /* Parent Closes connected socket */}}
Client code:
#include "unp.h" Const int SIZE = 1024;
void Input (FILE *fp, int sockfd) {int maxfdp1, stdineof;
Fd_set RSet;
Char Buf[maxline];
int n;
stdineof = 0;
Fd_zero (&rset); for (;;)
{if (stdineof = = 0) fd_set (Fileno (FP), &rset);
Fd_set (SOCKFD, &rset);
MAXFDP1 = Max (Fileno (FP), SOCKFD) + 1;
Select (MAXFDP1, &rset, NULL, NULL, NULL); if (Fd_isset (SOCKFD, &rset)) {* * * * * * is readable/if ((n = Read (SOCKFD, buf, maxline)) = = 0) {if stdin EOF = 1) return;
/* Normal termination */Else Err_quit ("Str_cli:server terminated prematurely");
Write (Fileno (stdout), buf, N);
} if (Fd_isset (Fileno (FP), &rset)) {*/* input is readable */if ((n = Read (Fileno (FP), buf, maxline)) = = 0) {
stdineof = 1; Shutdown (SOCKFD, SHUT_WR);
/* Send FIN/FD_CLR (Fileno (FP), &rset);
Continue
} writen (SOCKFD, buf, N);
int main (int argc, char **argv) {int sockfd; struct SockaDdr_in servaddr;
if (argc!= 3) err_quit ("Usage:tcpcli <IPaddress>::<Port>");
SOCKFD = Socket (af_inet, sock_stream, 0);
Bzero (&servaddr, sizeof (SERVADDR));
servaddr.sin_family = af_inet;
Servaddr.sin_port = htons (atoi (argv[2));
Inet_pton (Af_inet, argv[1], &servaddr.sin_addr);
Connect (SOCKFD, (SA *) &servaddr, sizeof (SERVADDR));
struct sockaddr_in SS;
socklen_t len = sizeof (ss);
if (GetSockName (SOCKFD, (SA *) &ss, &len) < 0) return 0; int clientport = Ntohs (Ss.sin_port); Pay attention the Translate n<->pstr_cli (stdin, SOCKFD);
/* Do it All/printf ("%d\n", ClientPort);
Input (stdin, SOCKFD);
Exit (0); }
Vim a paste, this code format I also helpless ...
To run through this code, you have to configure the UNP environment. Okay, I have the following interface code to do without configuring the UNP environment
Three. Add interface
I abstracted a few base classes, the main interface is 4, first look at the interface bar:
Server-side and the client's chat interface is the same, the server side I did a little processing, to deny multiple customer connections, when a customer chat, listening to the socket is closed.
Just learn QT began to engage in interface, it is disgusting.
Main code:
Client Login:
#include "clientstart.h" #include "chatclient.h" #include <iostream> #include <fstream> #include <
Sstream> using namespace std;
Clientstart::clientstart (Qwidget *parent): startbase (parent) {this->classname = "clientstart";
/*belong to the layout*/qlabel *labeloppositeip = new Qlabel ("Please enter server IP:");
Oppositeip = new Qlineedit;
Qlabel *labeloppositeport = new Qlabel ("Please enter Server port:");
Oppositeport = new Qlineedit;
Firstlayout->addwidget (LABELOPPOSITEIP, 2, 0, 1, 1);
Firstlayout->addwidget (OPPOSITEIP, 2, 1, 1, 4);
Firstlayout->addwidget (Labeloppositeport, 3, 0, 1, 1);
Firstlayout->addwidget (Oppositeport, 3, 1, 1, 4);
/*second layout*/secondlayout = new Qhboxlayout;
Secondlayout->setspacing (60);
Secondlayout->addwidget (buttonsure);
Secondlayout->addwidget (Buttoncancel);
Toplayout->addlayout (firstlayout);
Toplayout->addlayout (secondlayout); qwidget* widget = new QWidget (this);
Widget->setlayout (toplayout); This->setcentralwidget (widget);
Add the Toplayout in current dialog} Clientstart::~clientstart () {//delete this;}
void Clientstart::d oopen () {//qmessagebox::information (this, "Success", Qobject::tr ("xxx"), Qmessagebox::ok);
ServerIP = (Oppositeip->text ()). Tostdstring ();
ServerPort = (Oppositeport->text ()). Tostdstring ();
/*start Connect now*/bool Isconnect = Tryconnect ();
if (!isconnect) {Errorcall (this, "Connection failed");
return;
ChatClient cc (ClientIP, ClientPort, ServerIP, ServerPort, servaddr, CLIENTSOCKETFD);
Cc.exec ();
Cc.show ();
This->close ();
} void Clientstart::d ocancel () {qmessagebox::information (this, "failed", QOBJECT::TR ("Please reset"), Qmessagebox::ok);
Oppositeip->settext ("");
Oppositeport->settext ("");}
BOOL Clientstart::tryconnect () {CLIENTSOCKETFD = socket (af_inet, sock_stream, 0); Bzero (&servaddr, sizeof(SERVADDR));
servaddr.sin_family = af_inet;
Servaddr.sin_port = htons (Atoi (Serverport.c_str ()));
Inet_pton (Af_inet, Serverip.c_str (), &servaddr.sin_addr);
if (:: Connect (CLIENTSOCKETFD, (SA *) &servaddr, sizeof (SERVADDR)) < 0) return 0;
/*get client port, IP has already got*/struct sockaddr_in SS;
socklen_t len = sizeof (ss);
if (GetSockName (CLIENTSOCKETFD, (SA *) &ss, &len) < 0) return 0; StringStream stmp; change int to string stmp << Ntohs (ss.sin_port);
Pay attention the translate n<->p ClientPort = Stmp.str ();
return 1; }
Client Chat:
#include "chatclient.h" #include <iostream> #include <fstream> using namespace std; Chatclient::chatclient (std::string clientip, std::string clientport, std::string ServerIP, std::string serverPort,
struct sockaddr_in servaddr, int clientsocketfd): Chatbase (NULL) {this->clientip = ClientIP;
This->clientport = ClientPort;
This->serverip = ServerIP;
This->serverport = ServerPort;
THIS->SERVADDR = servaddr;
THIS->CLIENTSOCKETFD = CLIENTSOCKETFD;
This->linelocalip->settext (QString (Clientip.c_str ()));
This->linelocalport->settext (QString (Clientport.c_str ()));
This->lineoppositeip->settext (QString (Serverip.c_str ()));
This->lineoppositeport->settext (QString (Serverport.c_str ()));
This->secondlayout->setreadonly (1);
This->secondlayout->settext ("Start chatting now!\n");
This->secondlayout->append (ShowTime ());
This->secondlayout->show (); /*connECT the socket and function*/stdineof = 0;
Fd_zero (&rset);
REVSN = new Qsocketnotifier (CLIENTSOCKETFD, Qsocketnotifier::read);
Qobject::connect (REVSN, SIGNAL (activated (int)), this, SLOT (dodatareceived ()));
} chatclient::~chatclient () {stdineof = 1; Shutdown (CLIENTSOCKETFD, SHUT_WR);
/* Send FIN/Fd_zero (&rset);
This->close ();
} void ChatClient::d osendmsg () {std::string sent = (Forthlayout->toplaintext ()). Tostdstring ();
Sent + = ' \ n ';
if (Write (CLIENTSOCKETFD, Sent.c_str (), Sent.size ()) < 0) {Errorcall (this, "Send Message failed!");
return;
} appendsecondlayout (Sent);
Forthlayout->clear ();
} void ChatClient::d ocancel () {forthlayout->clear ();}
void ChatClient::d osendfile () {} void ChatClient::d ovedio () {} void ChatClient::d odatareceived () {int revlen; if ((Revlen = Read (CLIENTSOCKETFD, buf, maxline)) = = 0) {if (stdineof = 1) return; /* Normal termination */else {Errorcall (this, "server terminated prematurely");
This->close ();
} Buf[revlen] = ' I ';
Appendsecondlayout (String (BUF));
return; }
The server-side code is not released, and is basically similar.
I uploaded all the code to CSDN, link: Click on the Open link
Installation needs to configure QT5, video and transfer file function is not implemented
Four. Summary and future prospects
The software is also written to play, there must be bugs. In fact, the previous plan is to do NAT forwarding, so that the host between the two LAN can chat directly, and later found unworkable, do not have permission to modify the network routing NAT rules.
Future plans are as follows:
1. There is no QT interface, direct command line.
2. Implement file transfer.
3. Discard the C/s architecture, engage in a public network IP server, two chat host connected to this service at the same time, the server forwarding
If you have any questions to welcome the exchange, I hope to have a small partner with me to engage ~ ~.
Although the code is not difficult, but also oneself to buy and sell, reprint please specify address: http://blog.csdn.net/u011353822/article/details/41246277