Diseño de cursos de red informática Socket Network Chat

1.
Chat de red de Topic Socket

Dos, entorno
Windows10 VC6.0 ++

Tres, implementación de código

Ejemplo de uso de subprocesos múltiples

Socket utiliza un formato fijo y una configuración de parámetros, por lo que no se explica.
El subproceso múltiple consiste en lograr una comunicación de mensajes full-duplex, es decir, tanto el cliente como el servidor pueden enviar múltiples mensajes de forma continua. Un hilo es para recibir mensajes y otro hilo es para enviar mensajes.
Tanto el servidor como el cliente deben ingresar primero el nombre de usuario.Cuando todos los mensajes se imprimen en la línea de comandos, el nombre de usuario se imprime para facilitar la identificación de quién envió el mensaje.
Ya sea un servidor o un cliente, ingrese q, el socket se cerrará y la conexión se desconectará.

Servidor:


#include <stdio.h>
#include"stdafx.h"
#include <Winsock2.h>
#include <process.h>
#include <windows.h>
#include <String.h>
#include <stdlib.h>
#pragma comment(lib,"ws2_32")
SOCKET sockConn;
int send_len = 0;
int recv_len = 0;
int user_len = 0;
char usernameI[20];
char usernameU[20];
void send(void *){
    
    
		char c[50];
		printf("请输入用户名:\n");
	gets(usernameI);
	send_len = send(sockConn,usernameI,strlen(usernameI)+1,0);
	if(send_len < 0){
    
    
			printf("用户名发送失败!\n");
		}
	while(1){
    
    
		c[0]='\0';
	    gets(c);
		if(c[0] == 'q' && strlen(c) == 1){
    
    
			printf("套接字已关闭,连接断开!\n");
			closesocket(sockConn);
			WSACleanup();
			break;
		}
		send_len = send(sockConn,c,strlen(c)+1,0); 
		if(send_len < 0){
    
    
			printf("发送失败!\n");
		}
		
	}
	_endthread();
}
void resc(void *){
    
    
	int i=1;
	char recvBuf[50];
	int recv_len = recv(sockConn,recvBuf,50,0);
	if(recv_len < 0){
    
    
		printf("接收失败!\n");
	}else if(recv_len > 0){
    
    
		strcpy(usernameU,recvBuf);
	}
	while(1){
    
    
		recvBuf[0]='\0';
		//printf("recv的前面\n");
		recv_len = recv(sockConn,recvBuf,50,0);//会阻塞
		//printf("我在recv的后面了\n");
		if(recv_len < 0){
    
    
			printf("接收失败!\n");
			break;
		}else if(recv_len > 0){
    
    
			printf("%s:%s\n",usernameU,recvBuf);
		}
	}
	_endthread();
}

void main() 
{
    
    
 WORD wVersionRequested;
 WSADATA wsaData;
 int err;
 wVersionRequested = MAKEWORD( 1, 1 );

 err = WSAStartup( wVersionRequested, &wsaData );
 if ( err != 0 ) {
    
    
	 printf("初始化套接字库失败!\n");
	 return;
 }
 else{
    
    
	 printf("初始化套接字库成功!\n");
 }

 if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {
    
    
	 printf("套接字库版本号不符!\n");
 WSACleanup( );
 return;
 }else{
    
    
	 printf("套接字库版本正确!\n");
 }
SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);
 SOCKADDR_IN addrSrv;
 addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
 addrSrv.sin_family=AF_INET;
 addrSrv.sin_port=htons(6000);

 if(bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)) == SOCKET_ERROR){
    
    
	printf("套接字绑定失败!\n");
 }else{
    
    
	 printf("套接字绑定成功!\n");
	}
 if(listen(sockSrv,5) < 0){
    
    
	 printf("设置监听状态失败!\n");
 }else{
    
    
	 printf("设置监听状态成功!\n");
 }
 SOCKADDR_IN addrClient;
 int len=sizeof(SOCKADDR);
 while((sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len))==SOCKET_ERROR);
 if(sockConn == SOCKET_ERROR){
    
    
	 printf("连接失败!\n");
	 WSACleanup();
 }
 printf("输入q聊天结束\n");
 _beginthread(resc,0,NULL);
 _beginthread(send,0,NULL);
 while(1);
printf("end\n");
 
}



Cliente:

#include <stdio.h>
#include"stdafx.h"
#include <Winsock2.h>
#include <process.h>
#include <String.h>
#include <windows.h>
#include <stdlib.h>
#pragma comment(lib,"ws2_32")
int send_len = 0;
int recv_len = 0;
char usernameI[20];
char usernameU[20];
SOCKET sockClient;
void send(void *){
    
    
	char c[50];
	printf("请输入用户名:\n");
	gets(usernameI);
	send_len = send(sockClient,usernameI,strlen(usernameI)+1,0);
	if(send_len < 0){
    
    
			printf("用户名发送失败!\n");
		}
	while(1){
    
    
		c[0]='\0';
		gets(c);
		if(c[0] == 'q' && strlen(c) == 1){
    
    
			printf("套接字已关闭,连接断开\n");
			closesocket(sockClient);
			WSACleanup();
			break;
		}
		send_len = send(sockClient,c,strlen(c)+1,0);
		if(send_len < 0){
    
    
			printf("发送失败!\n");
		}		
	}
	
}

void resc(void *){
    
    
	char recvBuf[50];
	int recv_len = recv(sockClient,recvBuf,50,0);
	if(recv_len < 0){
    
    
		printf("接收失败!\n");
	}else if(recv_len > 0){
    
    
		strcpy(usernameU,recvBuf);
	}
	while(1){
    
    
		recvBuf[0]='\0';
	int recv_len = recv(sockClient,recvBuf,50,0);
	if(recv_len < 0){
    
    
		printf("接收失败!\n");
		break;
	}else if(recv_len > 0){
    
    
		printf("%s:%s\n",usernameU,recvBuf);
	}
	}
	_endthread();
}

void main()
{
    
    
 WORD wVersionRequested;
 WSADATA wsaData;
 int err;

 wVersionRequested = MAKEWORD( 1, 1 );

 err = WSAStartup( wVersionRequested, &wsaData );
 if ( err != 0 ) {
    
    
	 printf("初始化套接字库失败!\n");
 return;
 }else{
    
    
	 printf("初始化套接字库成功!\n");
 }
 if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {
    
    
	 printf("套接字库版本号不符!\n");
 WSACleanup( );
 return;
 }else{
    
    
	 printf("套接字版本号正确!\n");
 }
 sockClient=socket(AF_INET,SOCK_STREAM,0);
 SOCKADDR_IN addrSrv;
 addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
 addrSrv.sin_family=AF_INET;
 addrSrv.sin_port=htons(6000); 
 if(connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)) == SOCKET_ERROR){
    
    
	 printf("服务器连接失败!\n");
		 WSACleanup();
 }else{
    
    
	 printf("服务器连接成功!\n");
 }
 printf("输入q聊天结束\n");
 _beginthread(resc,0,NULL);
  _beginthread(send,0,NULL);
 while(1);
 printf("end\n");
} 

4. Resultados experimentales
Servidor

Cliente

V. Resumen y cosecha

Al principio, utilicé la función scanf para ingresar la declaración, y luego la declaración de impresión de la línea de comando no pudo mostrar instantáneamente la declaración recibida esta vez, pero la declaración recibida la última vez. La razón de mi propio análisis es que las funciones printf y scanf pueden estar bloqueadas en la línea de comando, lo que resulta en la imposibilidad de mostrar mensajes inmediatamente. Utilice la función get para ingresar la declaración, la línea de comando puede mostrar la declaración recibida actualmente de forma normal e instantánea.


Si tiene alguna pregunta, deje un mensaje para intercambiar.

Supongo que te gusta

Origin blog.csdn.net/weixin_43752257/article/details/112685537
Recomendado
Clasificación