多线程服务器

Linux下的socket通信

最近再学多线程的一些知识,刚好项目需求需要一个多线程的服务器,就现学现卖搭了一个服务器(数据库搭载mysql , 贴出一个登录模块 ,写的不好手下留情,刚接触不久)
1、Linux搭载mysql,有很多大佬的博客都有详细教程,这里就不搬运了。

#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <mysql/mysql.h>
#include <mysql/errmsg.h>
#include <mysql/mysqld_error.h>
#include "Function.h"
void* thread_routine(void* arg);
int clnt_num = 0;
int clnt_socks[CLNT_MAX];
pthread_mutex_t mutex;
pthread_t thread_id;
MYSQL mysql;
int main(int argc , char*argv[]){
	int serv_sock , clnt_sock , option , optlen;
	struct sockaddr_in serv_addr , clnt_addr;
	socklen_t clnt_addr_sz;
	MYSQL mysql;
	if(argc != 2)
	{
		printf("Usage : %s IP Port", argv[0]);
		exit(0);	
	}
	pthread_mutex_init(&mutex , NULL);
	serv_sock = socket(PF_INET , SOCK_STREAM , 0);
	if(serv_sock == -1)	
		error_handler("socket() filed");
	//**  地址再分配 **/
	optlen = sizeof(option);
	option = 1;
	setsockopt(serv_sock , SOL_SOCKET , SO_REUSEADDR , (void*)&option , optlen);
	memset(&serv_addr , 0 , sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(atoi(argv[1]));
	if(bind(serv_sock , (struct sockaddr*)&serv_addr , sizeof(serv_addr)) == -1)
		error_handler("bind() error");
	if(listen(serv_sock , 5) == -1)
		error_handler("connect() error");
	while(1){
		clnt_addr_sz = sizeof(clnt_addr);
		clnt_sock = accept(serv_sock , (struct sockaddr*)&clnt_addr , &clnt_addr_sz);
        if(clnt_sock == -1)
            continue;
		pthread_mutex_lock(&mutex);
		clnt_socks[clnt_num++] = clnt_sock;
		pthread_mutex_unlock(&mutex);
		pthread_create(&thread_id , NULL , thread_routine , (void*)&clnt_sock);
		pthread_detach(thread_id);
		printf("New client have connected and its IP is %s \n" , inet_ntoa(clnt_addr.sin_addr));
	}
	close(serv_sock);
	return 0;
}
void* thread_routine(void *arg) {
	int clnt_sock = *((int *)arg);
	MYSQL_RES *my_res;
	MYSQL_ROW my_row;
	while((str_len = read(clnt_sock , message , sizeof(message))) != 0) {
		printf("%d\n",str_len);
		if(str_len != -1){
			printf("message from client:%s\n" , message);
			mysql_init(&mysql);
			if(mysql_real_connect(&mysql , "localhost" , "root" , "12345678" , "test" , 0 , NULL , 0))
				printf("Connected database success\n");	
			else{
			    printf("Connected database failed \t error_message:%s" , mysql_error(&mysql));
				mysql_close(&mysql);  
				continue;
			}
			strcpy(msg_head, strtok(message, "#")); //执行此函数后原有字符串改变
			if (strcmp(msg_head, "01") == 0) {    //消息头部01代表注册
				//如果账号已经注册,就不用在注册提示用户已注册 
				strcpy(msg_phone, strtok(NULL, "#"));
				strcpy(msg_psd, strtok(NULL, "#"));
				strcpy(msg_username, strtok(NULL, "#"));		
				printf("%s , %s , %s\n" , msg_phone , msg_psd , msg_username);
				sprintf(sql, "select * from user where phone = %s", msg_phone);
				if (mysql_query(&mysql, sql) == 0){
					my_res = mysql_store_result(&mysql);
					if (my_res != NULL){ //查询表中无注册记录 , 需注册账号
						if(mysql_num_rows(my_res)){	
							printf("the user table have the register info: %lu\n" , (unsigned long)mysql_num_rows(my_res));
							write(clnt_sock , messagePrint(HAVE_REGISTER_INFO) , strlen(messagePrint(HAVE_REGISTER_INFO)));
						}else{
							sprintf(sql, "insert into user(user_name , phone , password) values ('%s' ,'%s' ,'%s')", msg_username, msg_phone, msg_psd);
							if (mysql_query(&mysql, sql) != 0){
								fprintf(stderr, "mysql_query failed:\n\tcode:%d\n\treason:%s\n",mysql_errno(&mysql), mysql_error(&mysql));
								write(clnt_sock , messagePrint(SQL_SENTENCE_ERROR) , strlen(messagePrint(SQL_SENTENCE_ERROR)));
							}else{					
								if(mysql_affected_rows(&mysql) != 0){
									printf("Insert success,affect row are %lu\n", mysql_affected_rows(&mysql));
									write(clnt_sock , messagePrint(REGISTER_OK) , strlen(messagePrint(REGISTER_OK)));
								}else{
									printf("Insert failed,affect row are %lu\n", mysql_affected_rows(&mysql));
									write(clnt_sock , messagePrint(REGISTER_ERROR) , strlen(messagePrint(REGISTER_ERROR)));
								}					
							}
						}
					}else		//已经有注册记录 , 返回注册提示信息		
						write(clnt_sock , messagePrint(MESSAGE_END) , strlen(messagePrint(MESSAGE_END)));
				}else{
					printf("error here\n");
					fprintf(stderr, "mysql_query failed:\n\tcode:%d\n\treason:%s\n", mysql_errno(&mysql), mysql_error(&mysql));
					write(clnt_sock , messagePrint(SQL_SENTENCE_ERROR) , strlen(messagePrint(SQL_SENTENCE_ERROR)));
				}			
			}
		}
		else{
			printf("The Client's data buffer have been clear\n");
		}
	}
	pthread_mutex_lock(&mutex);
	for(int i = 0; i < clnt_num ; i++){	//移除断开连接的客户端
		if(clnt_socks[i] == clnt_sock){
			while(i++ < clnt_num - 1)
				clnt_socks[i] = clnt_socks[i+1];
			printf("Disconnected Client's SocketFd: %d \n" , clnt_sock);
			mysql_free_result(my_res); 
			mysql_close(&mysql);
			break;
		}
	}
	clnt_num--;
	pthread_mutex_unlock(&mutex);
	close(clnt_sock);
	return NULL;		
}

2、头文件写函数,初步使用,还在做 ,后期调整

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CLNT_MAX 50
#define MAX_SIZE 1024 * 1024
#define ENUM_RETURN_MESSAGE(x) if(msg == x) return #x;
typedef enum
{
	SQL_SENTENCE_ERROR,
	REGISTER_OK,
	HAVE_REGISTER_INFO,
	REGISTER_ERROR,
	LOGIN_OK,
	USER_NOT_EXISTED,
	USER_OR_PASSWORD_ERROR,
	BIKE_ID_NOT_EXISTED,
	MESSAGE_END,
}RETURN_MESSAGE;
char* messagePrint(RETURN_MESSAGE msg)
{
	ENUM_RETURN_MESSAGE(SQL_SENTENCE_ERROR);
	ENUM_RETURN_MESSAGE(REGISTER_OK);
	ENUM_RETURN_MESSAGE(HAVE_REGISTER_INFO);
	ENUM_RETURN_MESSAGE(REGISTER_ERROR);
	ENUM_RETURN_MESSAGE(LOGIN_OK);
	ENUM_RETURN_MESSAGE(USER_NOT_EXISTED);
	ENUM_RETURN_MESSAGE(USER_OR_PASSWORD_ERROR);
	ENUM_RETURN_MESSAGE(BIKE_ID_NOT_EXISTED);
	return "Unknown_Error";
}
char message[MAX_SIZE];
char msg_head[5];       //客户端消息头部
char msg_phone[12];		//客户端消息—手机号
char msg_psd[9];	//客户端消息--密码
char msg_username[15];	//客户端消息---用户名
char bike_id[10];	//客户端消息------车辆编号
int str_len = 0;
char sql[100];	
void error_handler(char* msg)
{
	fputs(msg , stderr);
	fputs("\n" , stderr);
	exit(1);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值