socket网络通信

发布时间:2023年12月27日

通信模式

	1.点对点:一对一得通信
	2.客户机/服务器:一对多的通信

函数

/************Socket************************/
#include <sys/socket.h>
int socket (int domain, int type, int protocol);
/*
domain ,地址族
AF_UNIX/AF_LOCAL/AF_FILE: 本地通信(进程间通信);
 AF_INET: 基于TCP/IPv4(32位IP地址)的网络通信;
AF_INET6: 基于TCP/IPv6(128位IP地址)的网络通信;
AF_PACKET: 基于底层包接口的网络通信。

type,通信协议,
SOCK_STREAM ,数据流TCP
SOCK_DGRAM ,数据报协议UDP

protocol,特别通信协议,使用不多,置为0。
/************地址类型************************/
//成功返回套接字描述符,失败返回-1
*/
 //基本地址类型
struct sockaddr 
{
   sa_family_t sa_family;   // 地址族
   char        sa_data[14]; // 地址值
};

// 本地地址类型
#include <sys/un.h>
struct sockaddr_un 
{
    sa_family_t sun_family; // 地址族
    char        sun_path[]; // 套接字文件路径
};
 //网络地址类型
#include <netinet/in.h>
struct sockaddr_in 
{
    // 地址族
    sa_family_t sin_family;
    in_port_t sin_port;

    // IP地址
    struct in_addr sin_addr;
};
struct in_addr
{
    in_addr_t s_addr;
};
typedef uint32_t in_addr_t;

/************bind************************/
#include <sys/socket.h>
int bind (int sockfd, const struct sockaddr* addr,socklen_t addrlen);
//成功返回0,失败返回-1。

/************connect************************/

#include <sys/socket.h>
int connect (int sockfd, const struct sockaddr* addr,socklen_t addrlen);
//成功返回0,失败返回-1。



范例

server

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <netinet/in.h>
#include <assert.h>
#include <stdint.h>

#include "server_main.h"
#include "log.h"
#include "msgque.h"
#include "account.h"
#include "business.h"
#include "fileoper.h"
#include "slinkedlist.h"

#define PATH "/"
#define PROID1 100
#define PROID2 101

//全局变量  
int32_t sockfd = 0;
bool run = true;

void init(void){
	pLogFile = stdout;//打开LOG
	LOG_DEBUG("1、LOG日志已打开...\n");
	init_config();//加载配置
	LOG_DEBUG("2、配置加载中!...\n");
	AccountList = slinked_list_create(ASIZE);//创建链表
	LOG_DEBUG("3、创建链表!...\n");
	load_data();//加载数据
	LOG_DEBUG("4、链表数据加载中!...\n");
	load_base();//加载配置
	LOG_DEBUG("5、基本配置加载中!...\n");
}

static void sigint_proc(int32_t sig){
	LOG_DEBUG("服务器正在关闭!...\n");
	close(sockfd);
	if(save_data() != 0 || save_base() != 0){
		LOG_ERROR("数据保存失败!\n");
		return;
	}else{
		LOG_ERROR("数据保存成功!\n");
	}
	LOG_DEBUG("服务器关闭成功!...\n");
	run = false;
	exit(0);
}

void remove_client(int fd){
	int32_t i;
	pthread_rwlock_wrlock(&lock);
	for(i=0;i<size_acc;i++){
		if(fd == get_client[i].fd){
			close(fd);
			get_client[i] = get_client[--size_acc];
			break;
		}	
	}
	pthread_rwlock_unlock(&lock);
}

//线程函数
void* trans(void *arg){
	LOG_ERROR("%lu 线程链接\n",pthread_self());
	Client cls = *(Client*)arg;	
	Msg msg = {};
	pthread_rwlock_wrlock(&lock);
	get_client[size_acc++] = cls;
	pthread_rwlock_unlock(&lock);
	Account *pact = NULL;//记录登录的账户
	while(true){
		int32_t ret = msg_recv(cls.fd,&msg);
		if(ret == 0){
			pthread_rwlock_wrlock(&lock);
			LOG_ERROR("%lu 线程断开链接\n",pthread_self());
			remove_client(cls.fd);
			break;
		}
		//pthread_rwlock_wrlock(&lock);
		int32_t msgsz = business_entry(&msg,&pact);//msg作为入参  也作为出参
		//pthread_rwlock_unlock(&lock);
		msg_send(cls.fd,&msg,msgsz);//回复消息
	}	
}

void accept_client(int fd){
	Client cls = {};
	socklen_t len = sizeof(cls.addr);
	pthread_t id;
	int32_t ret = 0;
	while(true){
		cls.fd = accept(fd,(struct sockaddr*)&cls.addr,&len);
		assert(cls.fd != -1);
		ret = pthread_create(&id,NULL,trans,(void*)&cls);
		assert(ret == 0);
	}
} 

void server_run(const char *ip,const char *port){
	signal(SIGINT,sigint_proc);//Ctrl+C关闭服务器
	init();//初始化  加载配置文件 加载基础数据  创建消息队列
	LOG_DEBUG("按CTRL+C关闭服务器!...\n");
	// msgidr = msg_create(PATH,PROID1);
	// msgidw = msg_create(PATH,PROID2);
	// if(msgidr == -1 ||msgidw == -1){
	// 	exit(-1);	
	// }
	//打开网卡文件,得到文件描述符
	int32_t sock = socket(AF_INET,SOCK_STREAM,0);
	if(sock == -1){
		perror("socket");
		LOG_FATAL("socket is can't get!\n");
		exit(1);
	}

	struct sockaddr_in server;
	bzero(&server,sizeof(server));//使结构体server清零
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = inet_addr(ip);
	server.sin_port = htons(atoi(port));
	socklen_t len = sizeof(server);

	if(bind(sock,(struct sockaddr*)&server,len) < 0){
		perror("bind");
		LOG_FATAL("socket is can't bind!\n");
		exit(2);
	}
	//使sock处于监听状态,并且最多允许MAX_CLIENTS个客户端处于连接等待状态,多于MAX_CLIENTS的链接请求直接忽略
	if(listen(sock,MAX_CLIENTS) < 0){
		printf("listen error\n");
		LOG_FATAL("socket is can't listen!\n");
		exit(3);
	}
	accept_client(sock);
	//while(run){
		//从消息队列中读取一条消息
		// ret = msg_recv(msgidr,&msg,0);//接收消息
		// if(ret == -1){
		// 	LOG_ERROR("%s\n",strerror(errno));
		// 	break;
		// }
		// msgsz = business_entry(&msg);//msg作为入参 也作为出参 业务处理
		// ret = msg_send(msgidw,&msg,msgsz);//回消息 返回结果
		// if(ret == -1){
		// 	LOG_ERROR("%s\n",strerror(errno));
		// 	break;
		// }
	//}
}

client

#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
#include <assert.h>
#include "client_main.h"
#include "log.h"
#include "msgque.h"
#include "useroper.h"

#define PATH "/"
#define PRO1 100
#define PRO2 101

bool run = true;
int32_t fd;
int32_t msgsr = 0;

static void* client_entry(void *arg){
	Msg* msg =(Msg*)arg;
	msgsr = read_msg(msg);
	int32_t ret = msg_send(fd,msg,msgsr);
	if(ret == -1 || msg->type == 0){
		return;
	}
	ret = msg_recv(fd,msg);
	analyze_msg(msg);//服务器返回的结果
}

void client_run(const char *ip,const char *port){
	pLogFile = stdout;
	LOG_INFO("开始初始化!\n");	
	//创建套接字
	fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd == -1){
		perror("socket");
		return;
	}
//准备通信地址
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(atoi(port));
	addr.sin_addr.s_addr = inet_addr(ip);
	socklen_t len = sizeof(addr);
//连接通信	
	int32_t ret = connect(fd,(const struct sockaddr *)&addr,len);
	if(ret == -1){
		perror("connect");
		return;
	}
	Msg msg = {};
	//int32_t ret = 0;
	pthread_t id;
	while(run){
		ret = pthread_create(&id,NULL,client_entry,(void*)&msg);
		assert(ret == 0);
		pthread_join(id,NULL);
	}		
	/*
	size_t msgsz = 0;
	while(true){
		//读取用户的信息输入
		msgsz = read_msg(&msg);
		ret = msg_send(msgidw,&msg,msgsz);
		if(ret == -1 || msg.type==0){
			LOG_ERROR("发送消息队列失败!\n");
			break;	
		}
		ret = msg_recv(msgidr,&msg,0);
		analyze_msg(&msg);//服务器返回的结果
	}
	*/
}

文章来源:https://blog.csdn.net/qq_52575999/article/details/135243676
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。