Ideas
The main thread is responsible for sending messages, and the other thread is responsible for receiving messages. This is true for both the server and the client.
Attention
The port will not be shut down immediately after a party closes the socket port used for communication. Because at this time may B party's information has not finished send. Therefore, at this time a side of the recv is still in a blocking state, will eventually wait to receive information. At this point, when the B-party send a message to a, a-side recv, A's socket port is officially closed, A's recv return-1.
At this point, because the socket port of a is closed, B recv returns 0.
Code
This code server and the client program are written together. Please see the notes for details.
/************************************************************************* > File name:my_chat.c > Author: Krischou > Mail:[email protected] > Created time:thu 11:06:04 PM CST **************************** ********************************************/#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/inch.h>#include<arpa/inet.h>#include<unistd.h>#include<pthread.h>#include<netdb.h>#defineACTIVE 1#definePASSIVE 0#defineServer_port 1314#defineClient_port 1350/*receiving messages through thread implementations*/void* Chat_handler (void*Arg) { intFd_client = (int) Arg; Charbuf[1024x768]; inttest; while(Memset (BUF,0,1024x768), (Test=recv (Fd_client, buf,1024x768,0)) >0) {Write (1, buf, strlen (BUF)); } //used to test the recv return valueprintf"Break Child while!\n"); printf ("test =%d \ n", test); return(void*)0; //Close (fd_client);}intMainintargcChar* argv[])//exe PEER_IP{ intFlag; intFd_peer;/*the other side of the socket descriptor, returned by Acccept*/ if(ARGC = =1) {flag=PASSIVE; }Else if(ARGC = =2) {flag=ACTIVE; } /*---------------------------------------Socket----------------------------------------*/ intSFD;/*SFD as local socket descriptor*/SFD= Socket (Af_inet, Sock_stream,0) ; if(SFD = =-1) {perror ("Socket"); Exit (1); } /*---------------------------------------bind-----------------------------------------*/ Charmy_hostname[1024x768]=""; structHostent *p; GetHostName (My_hostname,1024x768);/*get local hostname to isolate IP based on hostname*/P= gethostbyname (My_hostname);/*gets a pointer to a struct hostent struct, according to hostname*/ structSockaddr_in local_addr;/*binding the socket port and the structure of the IP*/memset (&LOCAL_ADDR,0,sizeof(LOCAL_ADDR)); Local_addr.sin_family=af_inet; if(Flag = =ACTIVE) {Local_addr.sin_port= Htons (Client_port);/*as the active side, the port that needs to be bound is Client_port*/ }Else{Local_addr.sin_port= Htons (Server_port);/*as a server, you need to bind the port Server_port*/ /*both are native ports*/} local_addr.sin_addr= *(structIN_ADDR *) (P->h_addr_list) [0];/*Bind IP Address*/ /*Local IP*/ if(-1= = Bind (SFD, (structSOCKADDR *) &local_addr,sizeof(LOCAL_ADDR))) {Perror ("Bind"); Close (SFD); Exit (1); } /*----------------------------------If it is a server, listen+accept----------------------------------------------*/ if(Flag = =PASSIVE) { if(-1= = Listen (SFD,Ten) {perror ("Listen"); Close (SFD); Exit (1); } structSockaddr_in peer_addr;/*The structure that stores the contact information that returns the socket description characters is the outgoing parameter*/ intLen; memset (&PEER_ADDR,0,sizeof(PEER_ADDR)); Len=sizeof(PEER_ADDR); //Accept returns the other socket descriptor, and both PEER_ADDR and Len are outgoing parametersFd_peer = Accept (SFD, (structsockaddr*) &peer_addr,&Len); printf ("%s:%d begin to talk!\n", Inet_ntoa (PEER_ADDR.SIN_ADDR), Ntohs (Peer_addr.sin_port)); Close (SFD);//Kris}Else if(flag = = ACTIVE)/*-------------If the active side, connect-------------------------------------------------*/{Fd_peer= SFD;//if it is the active side, we are actually communicating from SFD. /*The active side to connect each other, need to know the other IP, through the command line parameters; also need to know the server port number, the program has been written dead*/ structsockaddr_in server_addr; memset (&SERVER_ADDR,0,sizeof(SERVER_ADDR)); Server_addr.sin_family=af_inet; Server_addr.sin_port= Htons (Server_port);/*add htons, if the right side is 12345678, to the left or 12345678, if not add htons if the right is 12345678, to the left will become 78563412*/server_addr.sin_addr.s_addr= Inet_addr (argv[1]); /*Connect does not connect to each other and returns-1, sleeps one second and continues to connect*/ while(Connect (SFD, (structsockaddr*) &server_addr,sizeof(SERVER_ADDR)) == -1) {Sleep (1); printf ("connecting....\n"); } printf ("success! \ n"); } pthread_t THD; Pthread_create (&THD, Null,chat_handler, (void*) fd_peer); Charmsg[1024x768]; while(Memset (MSG,0,1024x768), Fgets (MSG,1024x768, stdin)! =NULL) {Send (Fd_peer, MSG, strlen (msg),0); } close (Fd_peer); //for testingprintf"close close close \ n"); Pthread_join (THD, NULL); }/*This code communication is on Fd_peer this socket port*/
Program Run exit Results discussion
1. If a presses ctrl+d (the main thread exits the while loop, the close port is blocked on the pthread_join), then B sends a message at this time, a recv to and prints it in the thread, at which point A's socket port is really closed, RECV returns-1, Exit the loop, exit the thread, and a ends. b Because the socket port of a is closed, recv in the thread returns 0, exits the loop, and exits the thread. At this point B will exit the program if CTRL+D is pressed.
2. After one party presses the ctrl+d, the other party immediately presses the ctrl+d. The two sides were deadlocked. If one party presses CTRL + C, the other party will follow the withdrawal after forcing the program to exit. Cause: One side is strong, causing the socket port to really shut down, recv in the other side of the child thread returns 0, exits the loop, exits the thread.
3. A party comes up with CTRL + C strong back. The child thread of the other party will be returned, for the same reason. At this time the other party press Ctrl+d to exit the program.
Summary
The recv return value is divided into the following 3 cases
1. Greater than 0. The size of the data received.
2. Equals 0. The other side of the socket port is really closed.
3. Less than 0. Error. One such scenario is that the socket port of the party is actually closed, and attempts are made to fetch the data from that port.
The recv return value is actually similar to read.
Found
Send an empty message, as follows:
Send (Fd_peer,"",0,0);
The recv will not return 0, still blocked.
This differs from UDP in that, in UDP, one party sendto an empty message to the other, and the other's recvfrom returns 0.
Linux network programming 7--using TCP for both parties to chat