用C连接数据库服务器地址,核心就是通过数据库驱动API或ODBC接口,构造一个包含主机IP、端口、数据库名、用户名和密码的连接信息,然后调用对应的连接函数。 不管是C语言、C++还是C#,原理都是同一套:先初始化驱动,再发起连接,最后处理返回的错误码,别被各种库的差异吓到,把底层逻辑理清后,换数据库只是换一个连接字符串的事。
先搞清楚C连数据库的几种底层路径
很多人一上来就搜“用c怎么连接数据库服务器地址”,结果发现答案五花八门,因为C这个字包含了好几门语言,而且每门语言能走的路都不一样,我按实际开发中最高频的三种路径给你拆开。
直接调数据库官方API
这是C语言连接MySQL最原生的方式,官方提供一套libmysqlclient库,里面封装了连接、查询、关闭等函数,优点是没有中间层,性能最好,缺点是只能连MySQL,换数据库就要换代码。
具体到连接地址,就是mysql_real_connect函数里的第二个参数,这个参数可以填IP地址,比如"192.168.1.100",也可以填域名,比如"db.example.com",注意,这里不需要加协议头,也不需要写端口,端口是单独的参数。
用ODBC统一接口
ODBC(开放数据库互连)是微软主导的一套标准接口,C和C++都能用,它最大的价值是让你用同一套代码连接SQL Server、Oracle、MySQL、PostgreSQL等不同数据库,代价是你得先配置数据源名称(DSN)或直接写一个连接字符串。
对于SQL Server,连接字符串长这样:
Driver={ODBC Driver 17 for SQL Server};Server=192.168.1.20,1433;Database=testdb;Uid=sa;Pwd=your_password;
注意这里服务器地址和端口之间用的是逗号,不是冒号,这是SQL Server的习惯,和MySQL完全不同。
用封装库省心
C++开发里很多人用Qt的QSqlDatabase,或者用第三方库如libpq(PostgreSQL),C#则直接用ADO.NET的SqlConnection类,这些封装库本质上还是调驱动,但帮你省去了处理错误码、内存释放这些脏活累活,如果你的项目允许引入框架,优先走这条路,开发效率高不少。
c语言连接mysql数据库服务器地址的完整步骤
这个操作是你最可能遇到的场景,我以Linux环境为例,Windows下思路一样,就是装驱动和头文件的方式改成用vcpkg或直接下载MySQL Connector/C的zip包。
第一步:安装开发库和头文件
Ubuntu/Debian执行:
sudo apt-get install libmysqlclient-dev
CentOS/RHEL执行:
sudo yum install mysql-devel
Windows下,去MySQL官网下载Connector/C,注意选64位还是32位,要和你的编译环境匹配,装完后把lib和include路径配置到你的项目里。
第二步:写一个最小连接代码
直接上代码,你把服务器地址、用户名、密码换成你自己的就行。
#include <mysql.h> #include <stdio.h> int main() { MYSQL conn = mysql_init(NULL); if (conn == NULL) { fprintf(stderr, "mysql_init失败n"); return 1; } const char host = "192.168.1.10"; // 数据库服务器地址 const char user = "root"; // 用户名 const char passwd = "abc123"; // 密码 const char db = "test_db"; // 数据库名 unsigned int port = 3306; // 默认MySQL端口 if (mysql_real_connect(conn, host, user, passwd, db, port, NULL, 0) == NULL) { fprintf(stderr, "连接失败: %sn", mysql_error(conn)); mysql_close(conn); return 1; } printf("连接成功n"); mysql_close(conn); return 0; }
关键点有四个:
mysql_init(NULL)会分配一个连接对象,失败时返回NULL。mysql_real_connect的第二个参数是服务器地址,可以传IP或域名,如果服务器在本机,填localhost也行。- 第六个参数是端口,MySQL默认3306,如果你的服务器改了端口,比如用3307,这里必须对应改。
- 倒数第二个参数是
unix_socket,默认填NULL,最后一个client_flag默认填0,这两个不用纠结,后面需要开启特殊功能时再说。
第三步:编译时链接驱动库
写完代码后,编译命令不能漏了-lmysqlclient。
gcc connect.c -o connect -lmysqlclient
如果你用pkg-config管理库,也可以这么写:
gcc connect.c -o connect $(pkg-config --cflags --libs mysqlclient)
编译时报mysql.h: No such file or directory,大概率是没装开发包或include路径没配对,解压版的MySQL Connector/C还要手动指定-I和-L参数,这些坑很常见。
第四步:用错误输出定位问题
连接失败的报错信息里藏着关键线索,最常见的有几种:
Access denied for user 'root'@'192.168.1.5':用户名或密码错误,或者是root账号没权限从你的客户端IP远程登录。Unknown database 'test_db':数据库名拼错了,或者这个库压根不存在。Can't connect to MySQL server on '192.168.1.10' (110):服务器端口没通,可能是防火墙拦截,也可能是MySQL服务没启动。
遇到报错别慌,把mysql_error(conn)打印出来,一行一行看。
c++连接sqlserver服务器地址,和c语言真的不一样
C++连接SQL Server一般不直接用官方API,因为复杂度太高,行业共识认为,用ODBC或ADO是更实际的选择,尤其当你要连的服务器地址是内网IP加动态端口时,ODBC的灵活度明显更好。
先说连接字符串的写法
SQL Server的连接字符串格式比较绕,看这个模板:
Driver={ODBC Driver 18 for SQL Server};
Server=192.168.1.20,1433;
Database=testdb;
Encrypt=no;
UID=sa;
PWD=your_password;
注意几点:
- 服务器地址后必须跟逗号和端口,如果不写端口,SQL Server默认监听1433,但很多部署环境会改成其他端口,比如5400、54321,这时你必须显式加上。
Encrypt=no不是必须的,但最近版本的ODBC Driver默认启用加密,如果你服务器没配证书,反而不连不上,所以排障时可以先加上这个参数。- 登录方式有两种:SQL Server验证(用UID/PWD),或者Windows集成认证(用Trusted_Connection=yes),别混用。
用C++写一段ODBC连接代码
这里用SQLDriverConnect函数演示:
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <iostream>
int main() {
SQLHENV env;
SQLHDBC dbc;
SQLRETURN ret;
ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
SQLCHAR connStr[] = "DRIVER={ODBC Driver 18 for SQL Server};SERVER=192.168.1.20,1433;DATABASE=testdb;UID=sa;PWD=123;";
SQLCHAR outConn[1024] = {0};
SQLSMALLINT outLen;
ret = SQLDriverConnect(dbc, NULL, connStr, SQL_NTS, outConn, sizeof(outConn), &outLen, SQL_DRIVER_NOPROMPT);
if (SQL_SUCCEEDED(ret)) {
std::cout << "连接成功" << std::endl;
} else {
std::cout << "连接失败,错误码: " << ret << std::endl;
}
SQLDisconnect(dbc);
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
SQLFreeHandle(SQL_HANDLE_ENV, env);
return 0;
}
这段代码在Windows环境下编译需要链接odbc32.lib,Visual Studio里直接在项目属性里加依赖项就行,Linux下用unixODBC的话,头文件和库略有区别,但逻辑一致。
用ODBC测试工具先验证服务器地址可通
写代码之前,先用现成的工具测一下服务器地址,能省很多时间。
Windows上,在“控制面板 -> 系统管理工具 -> ODBC数据源(64位)”里创建一个DSN,填好服务器地址、端口、用户名、密码,点“测试连接”,如果这里能通,说明问题在你的代码里;如果这里都报错,直接排查网络和数据库配置。
Linux上可以用isql命令:
isql -v DSNName username password
如果isql能连上,那你用代码连时几乎不会出问题。
连接远程数据库服务器地址时,容易忽略的3个坑
你以为把IP和端口写对就能连上?太天真了,远程连接数据库服务器地址,真正卡人的往往是服务器端配置。
坑一:防火墙和安全组没放行端口
云服务器上,安全组规则经常默认只开放22和80,MySQL的3306端口、SQL Server的1433端口,通通没放行,你又不开防火墙端口,代码写得再对也没用,解决办法是去云控制台的安全组入站规则里,添加允许来源IP网段访问3306或1433的规则,服务器本地防火墙也要允许端口:
sudo ufw allow 3306/tcp
CentOS用firewall-cmd:
sudo firewall-cmd --zone=public --add-port=3306/tcp --permanent sudo firewall-cmd --reload
坑二:数据库服务本身只监听本地地址
MySQL默认配置bind-address=127.0.0.1,意思是你只能从本机连接,远程IP一律拒绝,检查一下my.cnf文件:
[mysqld] bind-address = 0.0.0.0 port = 3306
改完重启MySQL服务,SQL Server则需要在“SQL Server配置管理器”中启用TCP/IP协议,注意,这一步容易被漏掉,因为默认SQL Server只启用了Shared Memory和Named Pipes。
坑三:账号没有远程登录权限
即使数据库监听了所有IP,你的用户名也可能只能在本地登录,MySQL的授权表里,用户由“用户名@主机名”共同决定,比如'root'@'localhost'只能本机用,你需要创建一个允许任意主机连接的账号:
CREATE USER 'app_user'@'%' IDENTIFIED BY 'strong_password'; GRANT ALL PRIVILEGES ON test_db. TO 'app_user'@'%'; FLUSH PRIVILEGES;
或者直接授权给指定网段,SQL Server也类似,在“安全性 -> 登录名”里,设置能远程访问的权限。
Q&A:用c怎么连接数据库服务器地址?三个高频问题
问题1:mysql_real_connect最后一个参数到底填什么?
最后一个参数是client_flag,通常填0,如果查询语句包含多条用分号分隔的语句,或需要查询结果返回字段元数据,可以按位或上CLIENT_MULTI_STATEMENTS等宏,但初学阶段填0完全够用,如果你连接的是Unix域套接字而不是TCP,需要把倒数第二个参数unix_socket设置为套接字文件路径,比如/var/run/mysqld/mysqld.sock,端口设为0。
问题2:为什么C语言连接服务器地址总报“Connection refused”?
这个报错说明你的网络包根本没到达数据库服务,按顺序排查:
- 先在客户端机器上执行
telnet 服务器IP 3306,看端口是否通,如果提示connection refused,说明服务没监听或防火墙拦截。 - 在服务器上执行
netstat -tlnp | grep 3306,看MySQL进程是否监听在0.0.0.0:3306,如果监听在127.0.0.1:3306,说明bind-address没改对。 - 检查安全组和云防火墙入站规则。
大多数情况下,问题出在端口没放行或bind-address没改。
问题3:C++连接SQL Server时,必须启用TCP/IP协议吗?
是的,SQL Server安装后,默认很可能只启用了“Shared Memory”和“Named Pipes”两种协议,这两种协议都走不了远程网络,你需要打开“SQL Server配置管理器”,在“SQL Server网络配置 -> 你的实例名 -> 协议”下,把“TCP/IP”的已启用状态改成“是”,然后在“IP地址”选项卡里确认IP和端口(默认1433),改完必须重启SQL Server服务才能生效,还有一个细节:如果SQL Server的动态端口打开了,那么每次服务启动端口都可能变,远程连接时宁可在连接字符串里写明固定端口,也别依赖动态端口。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/722318.html





