这是根据自己的笔记整理的,如有错误,欢迎指出来.
tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据.
在阻塞模式下,send函数的过程是将应用程序请求发送的数据拷贝到发送缓存中发送并得到确认后再返回.但由于发送缓存的存在,表现为:如果发送缓存大小比请求发送的大小要大,那么send函数立即返回,同时向网络中发送数据;否则,send向网络发送缓存中不能容纳的那部分数据,并等待对端确认后再返回(接收端只要将数据收到接收缓存中,就会确认,并不一定要等待应用程序调用recv);
在非阻塞模式下,send函数的过程仅仅是将数据拷贝到协议栈的缓存区而已,如果缓存区可用空间不够,则尽能力的拷贝,返回成功拷贝的大小;如缓存区可用空间为0,则返回-1,同时设置errno为EAGAIN.
linux下可用sysctl -a | grep net.ipv4.tcp_wmem查看系统默认的发送缓存大小:
net.ipv4.tcp_wmem = 4096 16384 81920
这有三个值,第一个值是socket的发送缓存区分配的最少字节数,第二个值是默认值(该值会被net.core.wmem_default覆盖),缓存区在系统负载不重的情况下可以增长到这个值,第三个值是发送缓存区空间的最大字节数(该值会被net.core.wmem_max覆盖).
根据实际测试,如果手工更改了net.ipv4.tcp_wmem的值,则会按更改的值来运行,否则在默认情况下,协议栈通常是按net.core.wmem_default和net.core.wmem_max的值来分配内存的.
应用程序应该根据应用的特性在程序中更改发送缓存大小:
socklen_t sendbuflen = 0;
socklen_t len = sizeof(sendbuflen);
getsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, &len);
printf("default,sendbuf:%d\n", sendbuflen);
sendbuflen = 10240;
setsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, len);
getsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, &len);
printf("now,sendbuf:%d\n", sendbuflen);
需要注意的是,虽然将发送缓存设置成了10k,但实际上,协议栈会将其扩大1倍,设为20k.
-------------------实例分析----------------------
在实际应用中,如果发送端是非阻塞发送,由于网络的阻塞或者接收端处理过慢,通常出现的情况是,发送应用程序看起来发送了10k的数据,但是只发送了2k到对端缓存中,还有8k在本机缓存中(未发送或者未得到接收端的确认).那么此时,接收应用程序能够收到的数据为2k.假如接收应用程序调用recv函数获取了1k的数据在处理,在这个瞬间,发生了以下情况之一:
A. 发送应用程序认为send完了10k数据,关闭了socket:
发送主机作为tcp的主动关闭者,连接将处于FIN_WAIT1的半关闭状态(等待对方的ack),并且,发送缓存中的8k数据并不清除,依然会发送给对端.如果接收应用程序依然在recv,那么它会收到余下的8k数据(这个前题是,接收端会在发送端FIN_WAIT1状态超时前收到余下的8k数据.),然后得到一个对端socket被关闭的消息(recv返回0).这时,应该进行关闭.
B. 发送应用程序再次调用send发送8k的数据:
假如发送缓存的空间为20k,那么发送缓存可用空间为20-8=12k,大于请求发送的8k,所以send函数将数据做拷贝后,并立即返回8192;
假如发送缓存的空间为12k,那么此时发送缓存可用空间还有12-8=4k,send()会返回4096,应用程序发现返回的值小于请求发送的大小值后,可以认为缓存区已满,这时必须阻塞(或通过select等待下一次socket可写的信号),如果应用程序不理会,立即再次调用send,那么会得到-1的值,在linux下表现为errno=EAGAIN.
C. 接收应用程序在处理完1k数据后,关闭了socket:
接收主机作为主动关闭者,连接将处于FIN_WAIT1的半关闭状态(等待对方的ack).然后,发送应用程序会收到socket可读的信号(通常是select调用返回socket可读),但在读取时会发现recv函数返回0,这时应该调用close函数来关闭socket(发送给对方ack);
如果发送应用程序没有处理这个可读的信号,而是继续调用send,那么第一次会像往常一样继续填充缓存区,然后返回,但如果再次调用send,进程会收到SIGPIPE信号,该信号的默认响应动作是退出进程.
D. 交换机或路由器的网络断开:
接收应用程序在处理完已收到的1k数据后,会继续从缓存区读取余下的1k数据,然后就表现为无数据可读的现象,这种情况需要应用程序来处理超时.一般做法是设定一个select等待的最大时间,如果超出这个时间依然没有数据可读,则认为socket已不可用.
发送应用程序会不断的将余下的数据发送到网络上,但始终得不到确认,所以缓存区的可用空间持续为0,这种情况也需要应用程序来处理.
如果不由应用程序来处理这种情况超时的情况,也可以通过tcp协议本身来处理,具体可以查看sysctl项中的:
net.ipv4.tcp_keepalive_intvl
net.ipv4.tcp_keepalive_probes
net.ipv4.tcp_keepalive_time
所以,要想编写优秀的socket程序也是很不容易的.特别是在为应用做优化时,很多工作都非常的烦琐.
来源:http://blog.chinaunix.net/u2/76292/showart.php?id=2406631
tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据.
在阻塞模式下,send函数的过程是将应用程序请求发送的数据拷贝到发送缓存中发送并得到确认后再返回.但由于发送缓存的存在,表现为:如果发送缓存大小比请求发送的大小要大,那么send函数立即返回,同时向网络中发送数据;否则,send向网络发送缓存中不能容纳的那部分数据,并等待对端确认后再返回(接收端只要将数据收到接收缓存中,就会确认,并不一定要等待应用程序调用recv);
在非阻塞模式下,send函数的过程仅仅是将数据拷贝到协议栈的缓存区而已,如果缓存区可用空间不够,则尽能力的拷贝,返回成功拷贝的大小;如缓存区可用空间为0,则返回-1,同时设置errno为EAGAIN.
linux下可用sysctl -a | grep net.ipv4.tcp_wmem查看系统默认的发送缓存大小:
net.ipv4.tcp_wmem = 4096 16384 81920
这有三个值,第一个值是socket的发送缓存区分配的最少字节数,第二个值是默认值(该值会被net.core.wmem_default覆盖),缓存区在系统负载不重的情况下可以增长到这个值,第三个值是发送缓存区空间的最大字节数(该值会被net.core.wmem_max覆盖).
根据实际测试,如果手工更改了net.ipv4.tcp_wmem的值,则会按更改的值来运行,否则在默认情况下,协议栈通常是按net.core.wmem_default和net.core.wmem_max的值来分配内存的.
应用程序应该根据应用的特性在程序中更改发送缓存大小:
socklen_t sendbuflen = 0;
socklen_t len = sizeof(sendbuflen);
getsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, &len);
printf("default,sendbuf:%d\n", sendbuflen);
sendbuflen = 10240;
setsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, len);
getsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (void*)&sendbuflen, &len);
printf("now,sendbuf:%d\n", sendbuflen);
需要注意的是,虽然将发送缓存设置成了10k,但实际上,协议栈会将其扩大1倍,设为20k.
-------------------实例分析----------------------
在实际应用中,如果发送端是非阻塞发送,由于网络的阻塞或者接收端处理过慢,通常出现的情况是,发送应用程序看起来发送了10k的数据,但是只发送了2k到对端缓存中,还有8k在本机缓存中(未发送或者未得到接收端的确认).那么此时,接收应用程序能够收到的数据为2k.假如接收应用程序调用recv函数获取了1k的数据在处理,在这个瞬间,发生了以下情况之一:
A. 发送应用程序认为send完了10k数据,关闭了socket:
发送主机作为tcp的主动关闭者,连接将处于FIN_WAIT1的半关闭状态(等待对方的ack),并且,发送缓存中的8k数据并不清除,依然会发送给对端.如果接收应用程序依然在recv,那么它会收到余下的8k数据(这个前题是,接收端会在发送端FIN_WAIT1状态超时前收到余下的8k数据.),然后得到一个对端socket被关闭的消息(recv返回0).这时,应该进行关闭.
B. 发送应用程序再次调用send发送8k的数据:
假如发送缓存的空间为20k,那么发送缓存可用空间为20-8=12k,大于请求发送的8k,所以send函数将数据做拷贝后,并立即返回8192;
假如发送缓存的空间为12k,那么此时发送缓存可用空间还有12-8=4k,send()会返回4096,应用程序发现返回的值小于请求发送的大小值后,可以认为缓存区已满,这时必须阻塞(或通过select等待下一次socket可写的信号),如果应用程序不理会,立即再次调用send,那么会得到-1的值,在linux下表现为errno=EAGAIN.
C. 接收应用程序在处理完1k数据后,关闭了socket:
接收主机作为主动关闭者,连接将处于FIN_WAIT1的半关闭状态(等待对方的ack).然后,发送应用程序会收到socket可读的信号(通常是select调用返回socket可读),但在读取时会发现recv函数返回0,这时应该调用close函数来关闭socket(发送给对方ack);
如果发送应用程序没有处理这个可读的信号,而是继续调用send,那么第一次会像往常一样继续填充缓存区,然后返回,但如果再次调用send,进程会收到SIGPIPE信号,该信号的默认响应动作是退出进程.
D. 交换机或路由器的网络断开:
接收应用程序在处理完已收到的1k数据后,会继续从缓存区读取余下的1k数据,然后就表现为无数据可读的现象,这种情况需要应用程序来处理超时.一般做法是设定一个select等待的最大时间,如果超出这个时间依然没有数据可读,则认为socket已不可用.
发送应用程序会不断的将余下的数据发送到网络上,但始终得不到确认,所以缓存区的可用空间持续为0,这种情况也需要应用程序来处理.
如果不由应用程序来处理这种情况超时的情况,也可以通过tcp协议本身来处理,具体可以查看sysctl项中的:
net.ipv4.tcp_keepalive_intvl
net.ipv4.tcp_keepalive_probes
net.ipv4.tcp_keepalive_time
所以,要想编写优秀的socket程序也是很不容易的.特别是在为应用做优化时,很多工作都非常的烦琐.
来源:http://blog.chinaunix.net/u2/76292/showart.php?id=2406631
101007 22:30:31 [ERROR] Can't open the mysql.plugin table. Please run the mysql_upgrade script to create it.
101007 22:30:31 [ERROR] Fatal error: Can't open and lock privilege tables: Table 'mysql.host' doesn't exist
101007 22:30:31 mysqld ended
再源码下面执行,如下:
linux-Jack-nb4:~/webserver/mysql-5.1.12-beta # ./scripts/mysql_install_db --user=mysql --datadir=/usr/local/mysql/var
Installing all prepared tables
Fill help tables
To start mysqld at boot time you have to copy support-files/mysql.server
to the right place for your system
PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !
To do so, start the server, then issue the following commands:
/usr/local/mysql/bin/mysqladmin -u root password 'new-password'
/usr/local/mysql/bin/mysqladmin -u root -h linux-Jack-nb4 password 'new-password'
See the manual for more instructions.
NOTE: If you are upgrading from a MySQL <= 3.22.10 you should run
the /usr/local/mysql/bin/mysql_fix_privilege_tables. Otherwise you will not be
able to use the new GRANT command!
You can start the MySQL daemon with:
cd /usr/local/mysql ; /usr/local/mysql/bin/mysqld_safe &
Please report any problems with the /usr/local/mysql/bin/mysqlbug script!
The latest information about MySQL is available on the web at
http://www.mysql.com
Support MySQL by buying support/licenses at http://shop.mysql.com
Mysql运行Ok了:
linux-Jack-nb4:~/webserver/mysql-5.1.12-beta # ps aux|grep mysql
root 5515 0.0 0.1 2804 1312 pts/0 S 22:40 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe
mysql 5566 0.3 1.6 81984 13132 pts/0 Sl 22:40 0:01 /usr/local/mysql/libexec/mysqld --basedir=/usr/local/mysql --datadir=/usr/local/mysql/var --user=mysql --pid-file=/usr/local/mysql/var/linux-Jack-nb4.pid --log-error=/usr/local/mysql/var/linux-Jack-nb4.err --socket=/tmp/mysql.sock --port=3306
前面指定了DB位置,后面就会对于那个--datadir=位置所在:
/usr/local/mysql/libexec/mysqld --basedir=/usr/local/mysql --datadir=/data/mysql-/ --user=mysql --pid-file=/data/mysql-//linux-jack-xiang.pid --log-error=/data/mysql-//linux-jack-xiang.err --socket=/tmp/mysql.sock --port=3306
root 5606 0.0 0.0 1900 652 pts/0 S+ 22:47 0:00 grep mysql
root 5515 0.0 0.1 2804 1312 pts/0 S 22:40 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe
mysql 5566 0.3 1.6 81984 13132 pts/0 Sl 22:40 0:01 /usr/local/mysql/libexec/mysqld --basedir=/usr/local/mysql --datadir=/usr/local/mysql/var --user=mysql --pid-file=/usr/local/mysql/var/linux-Jack-nb4.pid --log-error=/usr/local/mysql/var/linux-Jack-nb4.err --socket=/tmp/mysql.sock --port=3306
前面指定了DB位置,后面就会对于那个--datadir=位置所在:
/usr/local/mysql/libexec/mysqld --basedir=/usr/local/mysql --datadir=/data/mysql-/ --user=mysql --pid-file=/data/mysql-//linux-jack-xiang.pid --log-error=/data/mysql-//linux-jack-xiang.err --socket=/tmp/mysql.sock --port=3306
root 5606 0.0 0.0 1900 652 pts/0 S+ 22:47 0:00 grep mysql
在MYSQL启动老失败即:Starting MySQL.Manager of pid-file quit without updating file.[FAILED]
查看错误日志显示:mysqld_safe Starting mysqld daemon with databases from /usr/local/mysql/data
/usr/local/mysql/bin/mysqld: Table 'mysql.plugin' doesn't exist
Can't open the mysql.plugin table. Please run mysql_upgrade to create it.
InnoDB: The first specified data file ./ibdata1 did not exist:
编译命令
gcc -g connect_db.c -L/usr/lib/mysql -lmysqlclient -lz
注意:
如果 /tmp/ccTGmMS21.o: In function 'main':
/tmp/ccTGmMS21.o(.text+0x11): undefined reference to 'mysql_init'
那么参数增加-L参数
如果 /usr/lib/mysql/libmysqlclient.a(my_compress.o): In function 'my_uncompress':
my_compress.o(.text+0xaa): undefined reference to `uncompress'
那么增加-lz参数
如下问题,也是加上-lz:
/usr/local/mysql/lib/mysql//libmysqlclient.a(my_compress.o): In function `my_uncompress':
my_compress.c:(.text+0x60): undefined reference to `uncompress'
/usr/local/mysql/lib/mysql//libmysqlclient.a(my_compress.o): In function `my_compress_alloc':
my_compress.c:(.text+0x102): undefined reference to `compress'
/usr/local/mysql/lib/mysql//libmysqlclient.a(my_compress.o): In function `my_compress':
my_compress.c:(.text+0x1ae): undefined reference to `compress'
/usr/local/mysql/lib/mysql//libmysqlclient.a(my_compress.o): In function `unpackfrm':
my_compress.c:(.text+0x2bc): undefined reference to `uncompress'
/usr/local/mysql/lib/mysql//libmysqlclient.a(my_compress.o): In function `packfrm':
my_compress.c:(.text+0x3bb): undefined reference to `compress'
collect2: ld returned 1 exit status
如下:
gcc -g connect_db.c -L/usr/lib/mysql -lmysqlclient -lz
注意:
如果 /tmp/ccTGmMS21.o: In function 'main':
/tmp/ccTGmMS21.o(.text+0x11): undefined reference to 'mysql_init'
那么参数增加-L参数
如果 /usr/lib/mysql/libmysqlclient.a(my_compress.o): In function 'my_uncompress':
my_compress.o(.text+0xaa): undefined reference to `uncompress'
那么增加-lz参数
如下问题,也是加上-lz:
/usr/local/mysql/lib/mysql//libmysqlclient.a(my_compress.o): In function `my_uncompress':
my_compress.c:(.text+0x60): undefined reference to `uncompress'
/usr/local/mysql/lib/mysql//libmysqlclient.a(my_compress.o): In function `my_compress_alloc':
my_compress.c:(.text+0x102): undefined reference to `compress'
/usr/local/mysql/lib/mysql//libmysqlclient.a(my_compress.o): In function `my_compress':
my_compress.c:(.text+0x1ae): undefined reference to `compress'
/usr/local/mysql/lib/mysql//libmysqlclient.a(my_compress.o): In function `unpackfrm':
my_compress.c:(.text+0x2bc): undefined reference to `uncompress'
/usr/local/mysql/lib/mysql//libmysqlclient.a(my_compress.o): In function `packfrm':
my_compress.c:(.text+0x3bb): undefined reference to `compress'
collect2: ld returned 1 exit status
如下:
g++ -o out mysql_fetch_rows.cpp str.cpp str.h -I/usr/local/mysql/include/mysql/ -L/usr/local/mysql/lib/mysql/ -lmysqlclient -lz
apache 设置虚拟机为8080时候需要修改的地方:
1.httpd.conf
Listen 8080
2.<VirtualHost *:8080>
ServerAdmin jackxiang@tencent.com
1,2必须都要为:8080,否则没法访问8080端口,亲自试了试。
1.httpd.conf
Listen 8080
2.<VirtualHost *:8080>
ServerAdmin jackxiang@tencent.com
1,2必须都要为:8080,否则没法访问8080端口,亲自试了试。
apache 设置虚拟机为8080时候需要修改的地方:
1.httpd.conf
Listen 8080
2.<VirtualHost *:8080>
ServerAdmin jackxiang@tencent.com
1,2必须都要为:8080,否则没法访问8080端口,亲自试了试。
1.httpd.conf
Listen 8080
2.<VirtualHost *:8080>
ServerAdmin jackxiang@tencent.com
1,2必须都要为:8080,否则没法访问8080端口,亲自试了试。
Nginx虽然目前使用比较多,但还没有提供整合SVN的功能。
还只能是Apache配置SVN,Nginx作为代理。
nginx.conf设置:
apache使用的82端口,整合了SVN。
http://blog.ntsky.com/nginx-svn.html
我的使用方法:
一句简单命令重启nginx:
最近我的多个VPS经常出现502错误,经常需要重启nginx,但网上的很多教程都需要繁琐的启动脚本,远不如apache的重启命令那么简单。
但研究了一下nginx帮助后发现,有-s参数可对nginx服务进行管理:
# /usr/local/nginx/sbin/nginx -h
nginx version: nginx/0.7.63
Usage: nginx [-?hvVt] [-s signal] [-c filename] [-p prefix] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-s signal : send signal to a master process: stop, quit, reopen, reload-p prefix : set prefix path (default: /usr/local/nginx/)
-c filename : set configuration file (default: conf/nginx.conf)
-g directives : set global directives out of configuration file
于是我执行
# /usr/local/nginx/sbin/nginx -s reload
nginx已经重启成功。
apache 设置虚拟机为8080时候需要修改的地方:
1.httpd.conf
Listen 8080
2.<VirtualHost *:8080>
ServerAdmin jackxiang@tencent.com
1,2必须都要为:8080,否则没法访问8080端口,亲自试了试。
首先,调试通过apache的8080,然后再调试通过nginx的代理即可!!!
还只能是Apache配置SVN,Nginx作为代理。
nginx.conf设置:
server {
listen 80;
server_name ppsea.gicp.net;
location / {
root html;
index index.html index.htm;
proxy_pass http://192.168.1.10:82;
}
}
listen 80;
server_name ppsea.gicp.net;
location / {
root html;
index index.html index.htm;
proxy_pass http://192.168.1.10:82;
}
}
apache使用的82端口,整合了SVN。
http://blog.ntsky.com/nginx-svn.html
我的使用方法:
server {
listen 80;
server_name svn.qq.com;
location / {
root /usr/local/tads/htdocs/svn;
index index.html index.htm;
proxy_pass http://172.25.39.11*:8080;
}
}
listen 80;
server_name svn.qq.com;
location / {
root /usr/local/tads/htdocs/svn;
index index.html index.htm;
proxy_pass http://172.25.39.11*:8080;
}
}
一句简单命令重启nginx:
最近我的多个VPS经常出现502错误,经常需要重启nginx,但网上的很多教程都需要繁琐的启动脚本,远不如apache的重启命令那么简单。
但研究了一下nginx帮助后发现,有-s参数可对nginx服务进行管理:
# /usr/local/nginx/sbin/nginx -h
nginx version: nginx/0.7.63
Usage: nginx [-?hvVt] [-s signal] [-c filename] [-p prefix] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-s signal : send signal to a master process: stop, quit, reopen, reload-p prefix : set prefix path (default: /usr/local/nginx/)
-c filename : set configuration file (default: conf/nginx.conf)
-g directives : set global directives out of configuration file
于是我执行
# /usr/local/nginx/sbin/nginx -s reload
nginx已经重启成功。
apache 设置虚拟机为8080时候需要修改的地方:
1.httpd.conf
Listen 8080
2.<VirtualHost *:8080>
ServerAdmin jackxiang@tencent.com
1,2必须都要为:8080,否则没法访问8080端口,亲自试了试。
首先,调试通过apache的8080,然后再调试通过nginx的代理即可!!!
When installing PHP and MySQL on OSX you may get the error Can’t connect to local MySQL server through socket ‘/var/mysql/mysql.sock’. Or you may also get “No such file or directory” when calling mysql_connect from a PHP page. This occurs because PHP is looking for the file mysql.sock in it’s typical installation location of /var/mysql/mysql.sock. However the MySQL OSX installer actually puts the file in /tmp/mysql.sock. There are two easy ways to solve the problem.
Solution 1: Create a symbolic link
Open terminal and do the following:
sudo su
mkdir /var/mysql
ln -s /tmp/mysql.sock /var/mysql/mysql.sock
You just created a symbolic link in the place where PHP expects the socket file to be located so it should be happy.
Solution 2: Edit php.ini
If you don’t like the idea of creating a symbolic link, you can also simply alter your php.ini file to point PHP to the real location of mysql.sock.
Locate /etc/php.ini. (If php.ini doesn’t exist on your system, copy /etc/php.ini.default to /etc/php.ini). You will likely have to do this from the terminal unless you have Finder configured to show hidden files. Open the file and update the setting mysql.default_socket so it looks like this:
mysql.default_socket = /tmp/mysql.sock
To commit the change you need to restart Apache. You can do that in System Settings -> Sharing, then uncheck, then recheck Web Sharing.
注解:这个问题,在php和Mysql一台及其的时候特别需要注意,否则mysql没法连接上,而php -m|grep mysql 是有的,无法排查,而在链接其他IP机器是没有该问题的,注意下。
来源:http://verysimple.com/2009/01/07/php-on-os-cant-connect-to-local-mysql-server-through-socket-varmysqlmysqlsock/
Solution 1: Create a symbolic link
Open terminal and do the following:
sudo su
mkdir /var/mysql
ln -s /tmp/mysql.sock /var/mysql/mysql.sock
You just created a symbolic link in the place where PHP expects the socket file to be located so it should be happy.
Solution 2: Edit php.ini
If you don’t like the idea of creating a symbolic link, you can also simply alter your php.ini file to point PHP to the real location of mysql.sock.
Locate /etc/php.ini. (If php.ini doesn’t exist on your system, copy /etc/php.ini.default to /etc/php.ini). You will likely have to do this from the terminal unless you have Finder configured to show hidden files. Open the file and update the setting mysql.default_socket so it looks like this:
mysql.default_socket = /tmp/mysql.sock
To commit the change you need to restart Apache. You can do that in System Settings -> Sharing, then uncheck, then recheck Web Sharing.
注解:这个问题,在php和Mysql一台及其的时候特别需要注意,否则mysql没法连接上,而php -m|grep mysql 是有的,无法排查,而在链接其他IP机器是没有该问题的,注意下。
来源:http://verysimple.com/2009/01/07/php-on-os-cant-connect-to-local-mysql-server-through-socket-varmysqlmysqlsock/
将nobody用户添加到nogroup 组:
cat /etc/passwd|grep nobody
nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash
第3个字段是65534:意思就是,UID(用户的ID)是500.
第4个字段是65534:意思就是.GID(用户的组ID)的500.
使用usermod -g nogroup nobody就可以把已有的用户nobody加入nogroup 组了.
如下:
添加一个不能ssh登录的用户和制定用户的Home目录位置:
useradd -s /sbin/nologin -d /home/ftpuser -g ftp ftpuser
接下来给用户设置密码,否则此账号不能使用,命令如下
passwd ftpuser
这样就为linux系统添加用户testuser,用户目录指定为//home/ftpuser,属于ftp用户组,且此用户不能登陆系统。
添加移出(不需要加-a即可)组:
[root@webta_9090 ~]# usermod -a -Gappops liuzeyi
[root@webta_9090 ~]# id liuzeyi
uid=554(liuzeyi) gid=603(irdcops) groups=603(irdcops),601(appops)
[root@webta_9090 ~]# usermod -Girdcops liuzeyi
[root@webta_9090 ~]# id liuzeyi
uid=554(liuzeyi) gid=603(irdcops) groups=603(irdcops)
usermod -g nogroup nobody
cat /etc/passwd|grep nobody
nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash
第3个字段是65534:意思就是,UID(用户的ID)是500.
第4个字段是65534:意思就是.GID(用户的组ID)的500.
使用usermod -g nogroup nobody就可以把已有的用户nobody加入nogroup 组了.
如下:
:nobody:/var/lib/nobody:/bin/bash
添加一个不能ssh登录的用户和制定用户的Home目录位置:
useradd -s /sbin/nologin -d /home/ftpuser -g ftp ftpuser
接下来给用户设置密码,否则此账号不能使用,命令如下
passwd ftpuser
这样就为linux系统添加用户testuser,用户目录指定为//home/ftpuser,属于ftp用户组,且此用户不能登陆系统。
添加移出(不需要加-a即可)组:
[root@webta_9090 ~]# usermod -a -Gappops liuzeyi
[root@webta_9090 ~]# id liuzeyi
uid=554(liuzeyi) gid=603(irdcops) groups=603(irdcops),601(appops)
[root@webta_9090 ~]# usermod -Girdcops liuzeyi
[root@webta_9090 ~]# id liuzeyi
uid=554(liuzeyi) gid=603(irdcops) groups=603(irdcops)
linux可以使用lsof命令能查看到端口对应的进程号:
[root@www ~]# lsof -i
COMMAND PID USER FD TYPE DEVICESIZE NODE NAME
Sshd 2444 root 3u IPv4 7376 TCP 172.20.1.104:ssh (LISTEN)
Sshd 16187 root 3u IPv4 327678 TCP 172.20.1.104:ssh->172.20.1.181:56600 (ESTABLISHED)
在windows, 使用netstat -o参数:
-o 显示与每个连接相关的所属进程 ID。
来源:http://hi.baidu.com/fanniwz/blog/item/be108037a50f051b91ef3935.html
[root@www ~]# lsof -i
COMMAND PID USER FD TYPE DEVICESIZE NODE NAME
Sshd 2444 root 3u IPv4 7376 TCP 172.20.1.104:ssh (LISTEN)
Sshd 16187 root 3u IPv4 327678 TCP 172.20.1.104:ssh->172.20.1.181:56600 (ESTABLISHED)
在windows, 使用netstat -o参数:
-o 显示与每个连接相关的所属进程 ID。
来源:http://hi.baidu.com/fanniwz/blog/item/be108037a50f051b91ef3935.html
指针指向结构体数组实例
Unix/LinuxC技术 jackxiang 2010-12-28 22:56
#include <iostream>
using namespace std;
struct ENTINFO {
char ent_add[255];
};
typedef struct ENTINFO _ENTINFO;
int main(int argc, char *argv[])
{
_ENTINFO *ent_info_pointer;
_ENTINFO ent_info[1024];
memset(ent_info,0,sizeof(_ENTINFO)*1024);
strcpy(ent_info[0].ent_add,"guangdong shenzhen nanshan new haofang garden");
strcpy(ent_info[1].ent_add,"guangdong shenzhen nanshan haofang garden");
strcpy(ent_info[2].ent_add,"guangdong shenzhen nanshan haofang garden 6 floor");
ent_info_pointer = ent_info;
printf("ent_info_pointer->ent_add=%s\n",ent_info[0].ent_add);
printf("ent_info_pointer->ent_add=%s\n",ent_info[1].ent_add);
printf("ent_info_pointer->ent_add=%s\n",ent_info[2].ent_add);
printf("ent_info_pointer->ent_add=%s\n",ent_info_pointer->ent_add);
ent_info_pointer++;
printf("ent_info_pointer->ent_add=%s\n",ent_info_pointer->ent_add);
ent_info_pointer++;
printf("ent_info_pointer->ent_add=%s\n",ent_info_pointer->ent_add);
return 0;
}
using namespace std;
struct ENTINFO {
char ent_add[255];
};
typedef struct ENTINFO _ENTINFO;
int main(int argc, char *argv[])
{
_ENTINFO *ent_info_pointer;
_ENTINFO ent_info[1024];
memset(ent_info,0,sizeof(_ENTINFO)*1024);
strcpy(ent_info[0].ent_add,"guangdong shenzhen nanshan new haofang garden");
strcpy(ent_info[1].ent_add,"guangdong shenzhen nanshan haofang garden");
strcpy(ent_info[2].ent_add,"guangdong shenzhen nanshan haofang garden 6 floor");
ent_info_pointer = ent_info;
printf("ent_info_pointer->ent_add=%s\n",ent_info[0].ent_add);
printf("ent_info_pointer->ent_add=%s\n",ent_info[1].ent_add);
printf("ent_info_pointer->ent_add=%s\n",ent_info[2].ent_add);
printf("ent_info_pointer->ent_add=%s\n",ent_info_pointer->ent_add);
ent_info_pointer++;
printf("ent_info_pointer->ent_add=%s\n",ent_info_pointer->ent_add);
ent_info_pointer++;
printf("ent_info_pointer->ent_add=%s\n",ent_info_pointer->ent_add);
return 0;
}
运行结果:
ent_info_pointer->ent_add=guangdong shenzhen nanshan new haofang garden
ent_info_pointer->ent_add=guangdong shenzhen nanshan haofang garden
ent_info_pointer->ent_add=guangdong shenzhen nanshan haofang garden 6 floor
ent_info_pointer->ent_add=guangdong shenzhen nanshan new haofang garden
ent_info_pointer->ent_add=guangdong shenzhen nanshan haofang garden
ent_info_pointer->ent_add=guangdong shenzhen nanshan haofang garden 6 floor
strcture_array_test.cpp
root@17*.2*.38.78:~/c++/struct# ./a.out
No. Name sex age Score
10101Tom M 18 0
10102John M 19 0
10103Mary F 17 0
[实践OK]Linux下用Grep -E参数实现$grep -E ^[a-Z] supervisord.conf显示非注释项,ABC def abc,加上正则表达式实现,多个函数查找的方法,及实现查看所查找单词的前三行后两行的环绕搜索,grep一个多行单独IP间隔包含文字里的IP列表出来,grep查找时显示找到那行的后面N行-A,和前面N行参数-B的实际应用。
Php/Js/Shell/Go jackxiang 2010-12-28 20:14
cat xxxx.txt|grep -Ev "无锡|腾讯云|华为云|微软云|阿里云|百度云|金山云" #grep 正则接合v排除的查询
api-itv-xxxx-cn-master-php-db578496b-zxxnj 6/6 Running 0 65m
kubectl get po -l pro=itv_api|grep -E "Running +0" #加号+:匹配1个或多个前面的字符,它和星号*的作用相似,但它不匹配0个字符的情况。比如,"ab+c"将匹配"abc"、“abbc”、“abbb...c”等。
不用加正则参数也成,直接用egrep:
rpm -qf /bin/egrep
grep-2.20-3.el6_7.1.x86_64
rpm -ql grep-2.20-3.el6_7.1.x86_64|grep grep
/bin/egrep
/bin/fgrep
/bin/grep
cat videoupload.php |grep upload --color //给加点颜色。
背景:实现一次性查找多个函数的awk实现,以及grep一个文件里的所有IP行:
-n :grep 行输出,--line-number print line number with output lines
一)Grep -E参数,加上正则表达式实现,多个函数查找,如下:
配上shell 文件 findfunPath.sh如下:
简单示例:
二)查看所查找单词的前三行后两行的环绕搜索:
[root@iZ25dcp92ckZ multepoolserver]# grep -rin -B 3 -A 2 "pthread_create Failed" ./multepoolser.c
569- threadNum[i]=i;//给数组赋值,传入线程编号值,后传入线程里。
570- //if(pthread_create(&handleEpollRd[i],NULL,pthread_handle_message, (void *)&i)){
571- if(pthread_create(&handleEpollRd[i],NULL,pthread_handle_message, (void *)&threadNum[i])){
572: sprintf(errOut,"pthread_create Failed : %s - %m\n",strerror(errno));
573- loger(errOut);
574- return -1;
--
591- writeThreadNum[i]=i;//给数组赋值,传入线程编号值,后传入线程里。
592- //if(pthread_create(&saveUpFilePart2Diskk[i],NULL,sync_additional_writing_worker, NULL )){
593- if(pthread_create(&saveUpFilePart2Diskk[i],NULL,sync_additional_writing_worker, (void *)&writeThreadNum[i])){
594: sprintf(errOut,"pthread_create Failed : %s - %m\n",strerror(errno));
595- loger(errOut);
596- return -1;
三)grep一个多行单独IP间隔包含文字里的IP列表出来:
四)grep查找时显示找到那行的后面N行-A,和前面N行参数-B的实际应用之查找域名里的root有哪些路径:
grep -Er "common.jackxiang.com|vote.jackxiang.com|answer.jackxiang.com|scratch.jackxiang.com|api.itv.jackxiang.com|common.itv.jackxiang.com|api.itv.cctv.com|common.itv.cctv.com" ./ -A 7|grep root
./answer.jackxiang.com.conf- root /data/www/api.jackxiang.com/;
./api.itv.jackxiang.com.conf: root /data/www/api.itv.jackxiang.com/;
./vote.jackxiang.com.conf- root /data/www/api.jackxiang.com/;
./scratch.jackxiang.com.conf- root /data/www/api.jackxiang.com/;
./common.jackxiang.com.conf- root /data/www/api.jackxiang.com/;
api-itv-xxxx-cn-master-php-db578496b-zxxnj 6/6 Running 0 65m
kubectl get po -l pro=itv_api|grep -E "Running +0" #加号+:匹配1个或多个前面的字符,它和星号*的作用相似,但它不匹配0个字符的情况。比如,"ab+c"将匹配"abc"、“abbc”、“abbb...c”等。
不用加正则参数也成,直接用egrep:
rpm -qf /bin/egrep
grep-2.20-3.el6_7.1.x86_64
rpm -ql grep-2.20-3.el6_7.1.x86_64|grep grep
/bin/egrep
/bin/fgrep
/bin/grep
cat videoupload.php |grep upload --color //给加点颜色。
背景:实现一次性查找多个函数的awk实现,以及grep一个文件里的所有IP行:
-n :grep 行输出,--line-number print line number with output lines
一)Grep -E参数,加上正则表达式实现,多个函数查找,如下:
grep -Erin 'atoi|itoa|atol|ltoa|intval' ./
配上shell 文件 findfunPath.sh如下:
#!/bin/bash
findPath=$1
#judge folder is exist
if [ ! -d "$findPath" ]; then
echo "Sorry,Input path is not exist.";
echo "You can try follow command to check it: ls ${findPath}";
exit 0
fi
grep -Erin 'atoi|itoa|atol|ltoa|intval' ${findPath}|awk -F":" '{print "\nFileLineNumber=" $2 " ExistFileName=" $1 "\nDetailInfo
=" $0}'
findPath=$1
#judge folder is exist
if [ ! -d "$findPath" ]; then
echo "Sorry,Input path is not exist.";
echo "You can try follow command to check it: ls ${findPath}";
exit 0
fi
grep -Erin 'atoi|itoa|atol|ltoa|intval' ${findPath}|awk -F":" '{print "\nFileLineNumber=" $2 " ExistFileName=" $1 "\nDetailInfo
=" $0}'
简单示例:
findfunPath.sh /usr/local/pro/
二)查看所查找单词的前三行后两行的环绕搜索:
[root@iZ25dcp92ckZ multepoolserver]# grep -rin -B 3 -A 2 "pthread_create Failed" ./multepoolser.c
569- threadNum[i]=i;//给数组赋值,传入线程编号值,后传入线程里。
570- //if(pthread_create(&handleEpollRd[i],NULL,pthread_handle_message, (void *)&i)){
571- if(pthread_create(&handleEpollRd[i],NULL,pthread_handle_message, (void *)&threadNum[i])){
572: sprintf(errOut,"pthread_create Failed : %s - %m\n",strerror(errno));
573- loger(errOut);
574- return -1;
--
591- writeThreadNum[i]=i;//给数组赋值,传入线程编号值,后传入线程里。
592- //if(pthread_create(&saveUpFilePart2Diskk[i],NULL,sync_additional_writing_worker, NULL )){
593- if(pthread_create(&saveUpFilePart2Diskk[i],NULL,sync_additional_writing_worker, (void *)&writeThreadNum[i])){
594: sprintf(errOut,"pthread_create Failed : %s - %m\n",strerror(errno));
595- loger(errOut);
596- return -1;
三)grep一个多行单独IP间隔包含文字里的IP列表出来:
四)grep查找时显示找到那行的后面N行-A,和前面N行参数-B的实际应用之查找域名里的root有哪些路径:
grep -Er "common.jackxiang.com|vote.jackxiang.com|answer.jackxiang.com|scratch.jackxiang.com|api.itv.jackxiang.com|common.itv.jackxiang.com|api.itv.cctv.com|common.itv.cctv.com" ./ -A 7|grep root
./answer.jackxiang.com.conf- root /data/www/api.jackxiang.com/;
./api.itv.jackxiang.com.conf: root /data/www/api.itv.jackxiang.com/;
./vote.jackxiang.com.conf- root /data/www/api.jackxiang.com/;
./scratch.jackxiang.com.conf- root /data/www/api.jackxiang.com/;
./common.jackxiang.com.conf- root /data/www/api.jackxiang.com/;
使用Memcached实现Session共享
阅读全文

shell中如何一行写while:
From:http://blog.sina.com.cn/s/blog_ac843e330101c55g.html
if elif else demo:
wile demo:
函数示例:
From:http://blog.sina.com.cn/s/blog_ac843e330101c55g.html
if elif else demo:
#example
if [ $1 -gt 90 ];then
echo "Good, $1"
elif [ $1 -gt 70 ];then
echo "OK, $1"
else
echo "Bad, $1"
fi
if [ $1 -gt 90 ];then
echo "Good, $1"
elif [ $1 -gt 70 ];then
echo "OK, $1"
else
echo "Bad, $1"
fi
wile demo:
#example
i=1
sum=0
while test $i -le 100
do
let sum=$sum+$i
let i=$i+1
done
echo "1+2+3...+100="$sum
i=1
sum=0
while test $i -le 100
do
let sum=$sum+$i
let i=$i+1
done
echo "1+2+3...+100="$sum
函数示例:
#example
function add()
{
let $3=$1+$2
}
add 1 2 ret
echo $ret
function add()
{
let $3=$1+$2
}
add 1 2 ret
echo $ret
g r e p命令加- E参数,这一扩展允许使用扩展模式匹配。例如,要抽取城市代码为2 1 9或2 1 6,方法如下:
我采用:
~/grep# grep -Erin 'atoi|itoa|atol|ltoa' ./
./itoa.txt:1:itoa
./itoa.txt:2:atoi
./itoa.txt:3:atoi
./itoa.txt:4:atoi
./itoa.txt:5:atoi
./atoi.txt:1:atoi
./atoi.txt:2:atoi
./atoi.txt:3:atoi
./atoi.txt:4:atoi
./atoi.txt:5:atoi
./atol.txt:1:atol
./atol.txt:2:atol
./atol.txt:3:atol
./atol.txt:4:atol
./atol.txt:5:atol
./atol.txt:6:atol
./ltoa.txt:1:ltoa
./ltoa.txt:2:ltoa
./ltoa.txt:3:ltoa
./ltoa.txt:4:ltoa
./ltoa.txt:5:ltoa
./ltoa.txt:6:ltoa
阅读全文
[sam@chenwy sam]$ grep -E '219|216' data.f
219 dec 2CC1999 CAD 23.00 PLV2C 68
216 sept 3ZL1998 USP 86.00 KVM9E 234
219 dec 2CC1999 CAD 23.00 PLV2C 68
216 sept 3ZL1998 USP 86.00 KVM9E 234
我采用:
grep -Erin 'atoi|itoa|atol|ltoa' ./
~/grep# grep -Erin 'atoi|itoa|atol|ltoa' ./
./itoa.txt:1:itoa
./itoa.txt:2:atoi
./itoa.txt:3:atoi
./itoa.txt:4:atoi
./itoa.txt:5:atoi
./atoi.txt:1:atoi
./atoi.txt:2:atoi
./atoi.txt:3:atoi
./atoi.txt:4:atoi
./atoi.txt:5:atoi
./atol.txt:1:atol
./atol.txt:2:atol
./atol.txt:3:atol
./atol.txt:4:atol
./atol.txt:5:atol
./atol.txt:6:atol
./ltoa.txt:1:ltoa
./ltoa.txt:2:ltoa
./ltoa.txt:3:ltoa
./ltoa.txt:4:ltoa
./ltoa.txt:5:ltoa
./ltoa.txt:6:ltoa

亦庄,立足于北京国际新城的新高度,随着政策的利好导向,正在高速前行,成为北京在世界的代言。亦庄路东区作为以产业为主导功能的片区成为重点区域。丰富的交通资源为区域发展提供动力,亦庄线、M12线在此交会, 2010年年底开通的轻轨亦庄线,北接地铁5号线,20分钟直抵宋家庄。M12建成后通达国贸,将与CBD区域融合。
双轨建构 京南置业黄金点
距L2和M12换乘站经海路站仅280米VITA国际,于2010年11月11日破土动工, 11月12日售楼处开放。是目前北京距离地铁最近的在售低总价精装小户型,业主出门即可便捷接入北京城市地铁网。在经历通州、奥北、中关村等轻轨沿线不动产购置热潮之后,VITA国际的轨道效应将引领新一轮资本流向,开启全新地铁时代。
与VITA国际一个街区之隔,将建造亦庄的公交枢纽站,届时公交枢纽将实现“零距离”换乘。VITA国际门前双轨交会,瞬间直抵繁华。
保守估计:从开盘到交房每平米净赚4000非常轻松。仅供参考!
欢迎来电垂询:13269811169 陈娅婷
11月20日正式接受排号!排号可享受优惠!
双轨建构 京南置业黄金点
距L2和M12换乘站经海路站仅280米VITA国际,于2010年11月11日破土动工, 11月12日售楼处开放。是目前北京距离地铁最近的在售低总价精装小户型,业主出门即可便捷接入北京城市地铁网。在经历通州、奥北、中关村等轻轨沿线不动产购置热潮之后,VITA国际的轨道效应将引领新一轮资本流向,开启全新地铁时代。
与VITA国际一个街区之隔,将建造亦庄的公交枢纽站,届时公交枢纽将实现“零距离”换乘。VITA国际门前双轨交会,瞬间直抵繁华。
保守估计:从开盘到交房每平米净赚4000非常轻松。仅供参考!
欢迎来电垂询:13269811169 陈娅婷
11月20日正式接受排号!排号可享受优惠!
首先博主抛出一个疑问,如何实现windows和linux之间的rpc通信,这两个异构的系统如何才能建立变量传递通道,这相当困扰博主,如有好心人指点,将不胜感激。
好了,现在切入正题:今天博主在linux环境下实现了一个小小RPC通信,按照惯例,做一下总结吧。
原先博主用的是Red hat9,安装完red hat后不想系统不带GCC,然后博主跑遍各大linux论坛搜寻装GCC的步骤,虽然取得些微的进步,对linux也有一些初步的认识了,但是系统还是不能用。无奈,博主就跑去问老师如何解决linux安装C编译器,不想linux老师来了一句这个red hat他已经不玩好多年了,然后建议我去玩ubuntu。于是,博主就屁颠屁颠地跑去下载最新的ubuntu 10.4,然后安装。出乎意料的是,ubuntu安装要比red hat方便多了,基本属于傻瓜式操作。
所以,接下来博主要讲的基本都是基于ubuntu 10.4平台的。
虽然是新平台,但是ubuntu用的还是linux内核,所以基本和red hat差不多,只有些微差别。
这次操作比上次在red hat上操作顺利多了,博主是参照下文的步骤一步一步实现rpc的:
1. 根据rpc调用的功能,先不考虑rpc调用,编写一个平常的实现相应功能的程序。
如一个远程的文件传输的rpc调用,平常程序便是考虑文件存储在本地,直接打开读便可,如下:
#include <stdio.h>
#include <stdlib.h>
#define MAXNAME 20
#define MAXLENGTH 1024
char * readfile(char *);
int main()
{
char name[MAXNAME];
printf("Enter File Name: ");
scanf("%s", name);
printf("%s", readfile(name));
}
char * readfile(char * name)
{
FILE *file = fopen(name, "r");
char * buf = (char *)malloc(sizeof(char)*MAXLENGTH);
if (file == NULL)
{
printf("File Cann't Be Open!");
return 0;
}
printf("The File Content is : \n");
while (fgets(buf, MAXLENGTH-1, file) != NULL)
{
return buf;
}
return NULL;
}
2. 把程序拆分为两部分,main函数和readfile函数,带有main的一部分是主动发起调用的,在rpc中相当于客户端,带有readfile函数的部分是提供相应的功能的,相当于服务器端。将代码拆分后要在客户端添加相应的rpc调用函数,clnt_create(RMACHINE, FILETRANSPROG, FILETRANSVERS,"tcp");
FILETRANSPROG便是trans.x中的程序名,FILETRANSVERS是版本名,使用tcp进行rpc调用。
拆分后代码如下:
客户端client.c:
#include <rpc/rpc.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include "trans.h"
#define WSVERS MAKEWORD(0, 2)
#define RMACHINE "localhost"
CLIENT *handle;
#define MAXNAME 20
#define MAXLENGTH 1024
char * readfile(char *);
int main()
{
char name[MAXNAME];
char * buf;
printf("Enter File Name: ");
scanf("%s", name);
handle = clnt_create(RMACHINE, FILETRANSPROG, FILETRANSVERS,"tcp");
if (handle == 0) {
printf("Could Not Connect To Remote Server.\n");
exit(1);
}
buf = readfile(name);
printf("%s", buf);
return 0;
}
服务器端server.c:
#include <rpc/rpc.h>
#include <stdio.h>
#include <stdlib.h>
#include "trans.h"
#define MAXNAME 20
#define MAXLENGTH 1024
char * readfile(char * name)
{
FILE *file = fopen(name, "r");
char * buf = (char *)malloc(sizeof(char)*MAXLENGTH);
if (file == NULL)
{
printf("File Cann't Be Open!");
return 0;
}
printf("The File Content is : \n");
while (fgets(buf, MAXLENGTH-1, file) != NULL)
{
return buf;
}
return NULL;
}
3. 编写***.x文件。具体步骤可以参考Douglas的那本Internetworking With TCP/IP 的第三卷,客户端-服务器端编程与应用。
本程序的.x文件命名为trans.x内容如下:
const MAXLENGTH = 1024;
const MAXNAME = 20;
program FILETRANSPROG //程序名
{
version FILETRANSVERS //版本名
{
string READFILE(string) = 1; //调用的方法名
} = 1;
} = 99;
4. 使用rpcgen编辑.x文件,在linux下输入命令
rpcgen trans.x
若格式正确,编译无错误则产生三个文件trans.h,trans_svc.c(服务器端),trans_clnt.c(客户端)。因为上述trans.x中无自定义数据结构,所以没有xdr文件产生。
trans.h代码:
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#ifndef _TRANS_H_RPCGEN
#define _TRANS_H_RPCGEN
#include <rpc/rpc.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MAXLENGTH 1024
#define MAXNAME 20
#define FILETRANSPROG 99
#define FILETRANSVERS 1
#if defined(__STDC__) || defined(__cplusplus)
#define READFILE 1
extern char ** readfile_1(char **, CLIENT *);
extern char ** readfile_1_svc(char **, struct svc_req *);
extern int filetransprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
#else /* K&R C */
#define READFILE 1
extern char ** readfile_1();
extern char ** readfile_1_svc();
extern int filetransprog_1_freeresult ();
#endif /* K&R C */
#ifdef __cplusplus
}
#endif
#endif /* !_TRANS_H_RPCGEN */
trans_svc.c代码:
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#include "trans.h"
#include <stdio.h>
#include <stdlib.h>
#include <rpc/pmap_clnt.h>
#include <string.h>
#include <memory.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef SIG_PF
#define SIG_PF void(*)(int)
#endif
static void
filetransprog_1(struct svc_req *rqstp, register SVCXPRT *transp)
{
union {
char *readfile_1_arg;
} argument;
char *result;
xdrproc_t _xdr_argument, _xdr_result;
char *(*local)(char *, struct svc_req *);
switch (rqstp->rq_proc) {
case NULLPROC:
(void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
return;
case READFILE:
_xdr_argument = (xdrproc_t) xdr_wrapstring;
_xdr_result = (xdrproc_t) xdr_wrapstring;
local = (char *(*)(char *, struct svc_req *)) readfile_1;
break;
default:
svcerr_noproc (transp);
return;
}
memset ((char *)&argument, 0, sizeof (argument));
if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
svcerr_decode (transp);
return;
}
result = (*local)((char *)&argument, rqstp);
if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
svcerr_systemerr (transp);
}
if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
fprintf (stderr, "%s", "unable to free arguments");
exit (1);
}
return;
}
int
main (int argc, char **argv)
{
register SVCXPRT *transp;
pmap_unset (FILETRANSPROG, FILETRANSVERS);
transp = svcudp_create(RPC_ANYSOCK);
if (transp == NULL) {
fprintf (stderr, "%s", "cannot create udp service.");
exit(1);
}
if (!svc_register(transp, FILETRANSPROG, FILETRANSVERS, filetransprog_1, IPPROTO_UDP)) {
fprintf (stderr, "%s", "unable to register (FILETRANSPROG, FILETRANSVERS, udp).");
exit(1);
}
transp = svctcp_create(RPC_ANYSOCK, 0, 0);
if (transp == NULL) {
fprintf (stderr, "%s", "cannot create tcp service.");
exit(1);
}
if (!svc_register(transp, FILETRANSPROG, FILETRANSVERS, filetransprog_1, IPPROTO_TCP)) {
fprintf (stderr, "%s", "unable to register (FILETRANSPROG, FILETRANSVERS, tcp).");
exit(1);
}
svc_run ();
fprintf (stderr, "%s", "svc_run returned");
exit (1);
/* NOTREACHED */
}
trans_clnt.c代码:
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#include <memory.h> /* for memset */
#include "trans.h"
/* Default timeout can be changed using clnt_control() */
static struct timeval TIMEOUT = { 25, 0 };
char **
readfile_1(char **argp, CLIENT *clnt)
{
static char *clnt_res;
memset((char *)&clnt_res, 0, sizeof(clnt_res));
if (clnt_call (clnt, READFILE,
(xdrproc_t) xdr_wrapstring, (caddr_t) argp,
(xdrproc_t) xdr_wrapstring, (caddr_t) &clnt_res,
TIMEOUT) != RPC_SUCCESS) {
return (NULL);
}
return (&clnt_res);
}
5. 编写客户端和服务器端接口。此部分可以说是最麻烦的部分,稍不注意便会出错,同样可以参考Douglas的那本书,但要注意的是他的服务器接口例程代码中的每个函数的第二个参数应该是CLIENT *clnt, 而非struct svc_req * rqstp
为本程序编写的代码如下:
客户端接口文件trans_cif.c:
#include <rpc/rpc.h>
#include <stdio.h>
#include "trans.h"/* Client-side stub interface routines written by programmer */
extern CLIENT * handle;
static char **ret;
char * readfile(char * name)
{
char ** arg;
arg = &name;
ret = readfile_1(arg, handle);
return ret==NULL ? NULL : *ret;
}
服务器端接口文件trans_sif.c:
#include <rpc/rpc.h>
#include <stdio.h>
#include "trans.h"
char * readfile(char *);
static char * retcode;
char ** readfile_1(char ** w, CLIENT *clnt)
{
retcode = readfile(*(char**)w);
return &retcode;
}
6. 编译链接客户端和服务器端程序
不管是客户端还是服务器端,都要链接三个文件,
客户端:程序文件+*** _clnt.c+客户端接口文件。
服务器端:程序文件+*** _svc.c+服务器端接口文件
同时每一段的三个文件都是互相关联的,编译出现错误时,可以根据提示查看三个文件进行debug
命令如下:
gcc -Wall -o trans_client client.c trans_clnt.c trans_cif.c
gcc -Wall -o trans_server server.c trans_svc.c trans_sif.c
7. 启动服务器端和客户端,大功告成。要先运行服务器端程序,再运行客户端程序。命令如下:
./trans_server
./trans_client
client启动后,提示输入要传输的文件名,输入后,server将文件的第一行传回,大功告成!
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/symbol89/archive/2009/06/21/4285142.aspx
----------------------------------------------------------------------------------------------------------------------------------------------------
博主按照上面的指示一步一步做下来,还算顺利。但是在链接服务端文件时爆出一个错误,意思是trans_svc.c这个文件有个undefined reference to 'readfile_1_svc'错误,经本人亲测,是由于trans_svc.c文件第37行原本应该是local = (char*(*)(char *,struct svc_reg *))readfile_1;的,但是rpc编译器翻译成local = (char*(*)(char *,struct svc_reg *))readfile_1_svc ,所以把_svc去掉就好了。
这里不得不提的是ubuntu的vi编辑器相当不好用。即没有装vim,操作起来也没有red hat的vi编译器那样用的那么顺手。这里强烈推荐鸟哥的vi编辑器入门手册。把vi编译器介绍的很详细,附上地址:http://linux.vbird.org/linux_basic/0310vi.php。
vi编辑器模式图(转载自鸟哥的私房菜)
vi模式下指令汇总(转载自鸟哥的私房菜)
最后强烈推荐《鸟哥的私房菜》这本书,相当棒的讲解linux的一套书(有专门的网站)。分上下册,上册讲解linux的基本知识和指令,下册讲linux架站的知识。很实用。
-----------------------------------------------------------------------------------------------------------------------------------------------------
最后运行./trans_server时系统会爆出cannot connect to...的错误(具体的我也忘了),
Cannot register service: RPC: Unable to receive; errno = Connection refused
unable to register (FILETRANSPROG, FILETRANSVERS, udp)
这是由于linux默认把端口映射服务关闭的缘故。这时可以参照下面的解决方法:
centos 6(在CentOS 6.3当中,portmap服务由rpcbind负责) :
yum -y install nfs-utils rpcbind
我们可以看出NFS的安装在Centos 5下和Centos 6下还是有比较大的差异,做个记录方便以后安装。
$ sudo apt-get install nfs-kernel-server nfs-common portmap
$ sudo dpkg-reconfigure portmap
--------------------------------------------------------------------------------------------------------
如果启动还有问题,那有可能是rpcbind服务没有起得来:
[root@iZ25dcp92ckZ rpc]# service rpcbind start
Redirecting to /bin/systemctl start rpcbind.service
CeontOS参考:http://blog.chinaunix.net/uid-20639775-id-3399961.html
在出现如下提示的时候,注意选定“不将portmap 绑定在loopback 地址”
之后,系统会有如下提示:
Current registered services:
------------------------------------------------
100003 2 udp 2049 nfs
100003 3 udp 2049 nfs
100003 4 udp 2049 nfs
…
100003 2 tcp 2049 nfs
100003 3 tcp 2049 nfs
100003 4 tcp 2049 nfs
之后通过查看 /etc/default/portmap, 确保
#OPTIONS="-i 127.0.0.1"
前面的#号 被添加了
重启portmap服务:
$ sudo /etc/init.d/portmap restart
这样就可以了,但是要用root权限执行。
到这里所有我所遇到的问题都解决了,但是博主仍有疑问,如何实现windows和linux之间的rpc通信,这两个异构的系统如何才能建立变量传递通道,这相当困扰博主,如有好心人指点,将不胜感激。
======Below Add Time:2016-01-22=========
启动:
[root@iZ25dcp92ckZ rpc]# ./trans_server
连接:
[root@iZ25dcp92ckZ rpc]# ./trans_client
Enter File Name: /etc/hosts
127.0.0.1 iZ25dcp92ckZ Jack'sAliYunVPS jackxiang localhost
本文出自 “只争朝夕” 博客,请务必保留此出处http://xiaovfight.blog.51cto.com/1625426/398745
好了,现在切入正题:今天博主在linux环境下实现了一个小小RPC通信,按照惯例,做一下总结吧。
原先博主用的是Red hat9,安装完red hat后不想系统不带GCC,然后博主跑遍各大linux论坛搜寻装GCC的步骤,虽然取得些微的进步,对linux也有一些初步的认识了,但是系统还是不能用。无奈,博主就跑去问老师如何解决linux安装C编译器,不想linux老师来了一句这个red hat他已经不玩好多年了,然后建议我去玩ubuntu。于是,博主就屁颠屁颠地跑去下载最新的ubuntu 10.4,然后安装。出乎意料的是,ubuntu安装要比red hat方便多了,基本属于傻瓜式操作。
所以,接下来博主要讲的基本都是基于ubuntu 10.4平台的。
虽然是新平台,但是ubuntu用的还是linux内核,所以基本和red hat差不多,只有些微差别。
这次操作比上次在red hat上操作顺利多了,博主是参照下文的步骤一步一步实现rpc的:
1. 根据rpc调用的功能,先不考虑rpc调用,编写一个平常的实现相应功能的程序。
如一个远程的文件传输的rpc调用,平常程序便是考虑文件存储在本地,直接打开读便可,如下:
#include <stdio.h>
#include <stdlib.h>
#define MAXNAME 20
#define MAXLENGTH 1024
char * readfile(char *);
int main()
{
char name[MAXNAME];
printf("Enter File Name: ");
scanf("%s", name);
printf("%s", readfile(name));
}
char * readfile(char * name)
{
FILE *file = fopen(name, "r");
char * buf = (char *)malloc(sizeof(char)*MAXLENGTH);
if (file == NULL)
{
printf("File Cann't Be Open!");
return 0;
}
printf("The File Content is : \n");
while (fgets(buf, MAXLENGTH-1, file) != NULL)
{
return buf;
}
return NULL;
}
2. 把程序拆分为两部分,main函数和readfile函数,带有main的一部分是主动发起调用的,在rpc中相当于客户端,带有readfile函数的部分是提供相应的功能的,相当于服务器端。将代码拆分后要在客户端添加相应的rpc调用函数,clnt_create(RMACHINE, FILETRANSPROG, FILETRANSVERS,"tcp");
FILETRANSPROG便是trans.x中的程序名,FILETRANSVERS是版本名,使用tcp进行rpc调用。
拆分后代码如下:
客户端client.c:
#include <rpc/rpc.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include "trans.h"
#define WSVERS MAKEWORD(0, 2)
#define RMACHINE "localhost"
CLIENT *handle;
#define MAXNAME 20
#define MAXLENGTH 1024
char * readfile(char *);
int main()
{
char name[MAXNAME];
char * buf;
printf("Enter File Name: ");
scanf("%s", name);
handle = clnt_create(RMACHINE, FILETRANSPROG, FILETRANSVERS,"tcp");
if (handle == 0) {
printf("Could Not Connect To Remote Server.\n");
exit(1);
}
buf = readfile(name);
printf("%s", buf);
return 0;
}
服务器端server.c:
#include <rpc/rpc.h>
#include <stdio.h>
#include <stdlib.h>
#include "trans.h"
#define MAXNAME 20
#define MAXLENGTH 1024
char * readfile(char * name)
{
FILE *file = fopen(name, "r");
char * buf = (char *)malloc(sizeof(char)*MAXLENGTH);
if (file == NULL)
{
printf("File Cann't Be Open!");
return 0;
}
printf("The File Content is : \n");
while (fgets(buf, MAXLENGTH-1, file) != NULL)
{
return buf;
}
return NULL;
}
3. 编写***.x文件。具体步骤可以参考Douglas的那本Internetworking With TCP/IP 的第三卷,客户端-服务器端编程与应用。
本程序的.x文件命名为trans.x内容如下:
const MAXLENGTH = 1024;
const MAXNAME = 20;
program FILETRANSPROG //程序名
{
version FILETRANSVERS //版本名
{
string READFILE(string) = 1; //调用的方法名
} = 1;
} = 99;
4. 使用rpcgen编辑.x文件,在linux下输入命令
rpcgen trans.x
若格式正确,编译无错误则产生三个文件trans.h,trans_svc.c(服务器端),trans_clnt.c(客户端)。因为上述trans.x中无自定义数据结构,所以没有xdr文件产生。
trans.h代码:
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#ifndef _TRANS_H_RPCGEN
#define _TRANS_H_RPCGEN
#include <rpc/rpc.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MAXLENGTH 1024
#define MAXNAME 20
#define FILETRANSPROG 99
#define FILETRANSVERS 1
#if defined(__STDC__) || defined(__cplusplus)
#define READFILE 1
extern char ** readfile_1(char **, CLIENT *);
extern char ** readfile_1_svc(char **, struct svc_req *);
extern int filetransprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
#else /* K&R C */
#define READFILE 1
extern char ** readfile_1();
extern char ** readfile_1_svc();
extern int filetransprog_1_freeresult ();
#endif /* K&R C */
#ifdef __cplusplus
}
#endif
#endif /* !_TRANS_H_RPCGEN */
trans_svc.c代码:
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#include "trans.h"
#include <stdio.h>
#include <stdlib.h>
#include <rpc/pmap_clnt.h>
#include <string.h>
#include <memory.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef SIG_PF
#define SIG_PF void(*)(int)
#endif
static void
filetransprog_1(struct svc_req *rqstp, register SVCXPRT *transp)
{
union {
char *readfile_1_arg;
} argument;
char *result;
xdrproc_t _xdr_argument, _xdr_result;
char *(*local)(char *, struct svc_req *);
switch (rqstp->rq_proc) {
case NULLPROC:
(void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
return;
case READFILE:
_xdr_argument = (xdrproc_t) xdr_wrapstring;
_xdr_result = (xdrproc_t) xdr_wrapstring;
local = (char *(*)(char *, struct svc_req *)) readfile_1;
break;
default:
svcerr_noproc (transp);
return;
}
memset ((char *)&argument, 0, sizeof (argument));
if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
svcerr_decode (transp);
return;
}
result = (*local)((char *)&argument, rqstp);
if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
svcerr_systemerr (transp);
}
if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
fprintf (stderr, "%s", "unable to free arguments");
exit (1);
}
return;
}
int
main (int argc, char **argv)
{
register SVCXPRT *transp;
pmap_unset (FILETRANSPROG, FILETRANSVERS);
transp = svcudp_create(RPC_ANYSOCK);
if (transp == NULL) {
fprintf (stderr, "%s", "cannot create udp service.");
exit(1);
}
if (!svc_register(transp, FILETRANSPROG, FILETRANSVERS, filetransprog_1, IPPROTO_UDP)) {
fprintf (stderr, "%s", "unable to register (FILETRANSPROG, FILETRANSVERS, udp).");
exit(1);
}
transp = svctcp_create(RPC_ANYSOCK, 0, 0);
if (transp == NULL) {
fprintf (stderr, "%s", "cannot create tcp service.");
exit(1);
}
if (!svc_register(transp, FILETRANSPROG, FILETRANSVERS, filetransprog_1, IPPROTO_TCP)) {
fprintf (stderr, "%s", "unable to register (FILETRANSPROG, FILETRANSVERS, tcp).");
exit(1);
}
svc_run ();
fprintf (stderr, "%s", "svc_run returned");
exit (1);
/* NOTREACHED */
}
trans_clnt.c代码:
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#include <memory.h> /* for memset */
#include "trans.h"
/* Default timeout can be changed using clnt_control() */
static struct timeval TIMEOUT = { 25, 0 };
char **
readfile_1(char **argp, CLIENT *clnt)
{
static char *clnt_res;
memset((char *)&clnt_res, 0, sizeof(clnt_res));
if (clnt_call (clnt, READFILE,
(xdrproc_t) xdr_wrapstring, (caddr_t) argp,
(xdrproc_t) xdr_wrapstring, (caddr_t) &clnt_res,
TIMEOUT) != RPC_SUCCESS) {
return (NULL);
}
return (&clnt_res);
}
5. 编写客户端和服务器端接口。此部分可以说是最麻烦的部分,稍不注意便会出错,同样可以参考Douglas的那本书,但要注意的是他的服务器接口例程代码中的每个函数的第二个参数应该是CLIENT *clnt, 而非struct svc_req * rqstp
为本程序编写的代码如下:
客户端接口文件trans_cif.c:
#include <rpc/rpc.h>
#include <stdio.h>
#include "trans.h"/* Client-side stub interface routines written by programmer */
extern CLIENT * handle;
static char **ret;
char * readfile(char * name)
{
char ** arg;
arg = &name;
ret = readfile_1(arg, handle);
return ret==NULL ? NULL : *ret;
}
服务器端接口文件trans_sif.c:
#include <rpc/rpc.h>
#include <stdio.h>
#include "trans.h"
char * readfile(char *);
static char * retcode;
char ** readfile_1(char ** w, CLIENT *clnt)
{
retcode = readfile(*(char**)w);
return &retcode;
}
6. 编译链接客户端和服务器端程序
不管是客户端还是服务器端,都要链接三个文件,
客户端:程序文件+*** _clnt.c+客户端接口文件。
服务器端:程序文件+*** _svc.c+服务器端接口文件
同时每一段的三个文件都是互相关联的,编译出现错误时,可以根据提示查看三个文件进行debug
命令如下:
gcc -Wall -o trans_client client.c trans_clnt.c trans_cif.c
gcc -Wall -o trans_server server.c trans_svc.c trans_sif.c
7. 启动服务器端和客户端,大功告成。要先运行服务器端程序,再运行客户端程序。命令如下:
./trans_server
./trans_client
client启动后,提示输入要传输的文件名,输入后,server将文件的第一行传回,大功告成!
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/symbol89/archive/2009/06/21/4285142.aspx
----------------------------------------------------------------------------------------------------------------------------------------------------
博主按照上面的指示一步一步做下来,还算顺利。但是在链接服务端文件时爆出一个错误,意思是trans_svc.c这个文件有个undefined reference to 'readfile_1_svc'错误,经本人亲测,是由于trans_svc.c文件第37行原本应该是local = (char*(*)(char *,struct svc_reg *))readfile_1;的,但是rpc编译器翻译成local = (char*(*)(char *,struct svc_reg *))readfile_1_svc ,所以把_svc去掉就好了。
这里不得不提的是ubuntu的vi编辑器相当不好用。即没有装vim,操作起来也没有red hat的vi编译器那样用的那么顺手。这里强烈推荐鸟哥的vi编辑器入门手册。把vi编译器介绍的很详细,附上地址:http://linux.vbird.org/linux_basic/0310vi.php。
vi编辑器模式图(转载自鸟哥的私房菜)
vi模式下指令汇总(转载自鸟哥的私房菜)
最后强烈推荐《鸟哥的私房菜》这本书,相当棒的讲解linux的一套书(有专门的网站)。分上下册,上册讲解linux的基本知识和指令,下册讲linux架站的知识。很实用。
-----------------------------------------------------------------------------------------------------------------------------------------------------
最后运行./trans_server时系统会爆出cannot connect to...的错误(具体的我也忘了),
Cannot register service: RPC: Unable to receive; errno = Connection refused
unable to register (FILETRANSPROG, FILETRANSVERS, udp)
这是由于linux默认把端口映射服务关闭的缘故。这时可以参照下面的解决方法:
centos 6(在CentOS 6.3当中,portmap服务由rpcbind负责) :
yum -y install nfs-utils rpcbind
我们可以看出NFS的安装在Centos 5下和Centos 6下还是有比较大的差异,做个记录方便以后安装。
$ sudo apt-get install nfs-kernel-server nfs-common portmap
$ sudo dpkg-reconfigure portmap
--------------------------------------------------------------------------------------------------------
如果启动还有问题,那有可能是rpcbind服务没有起得来:
[root@iZ25dcp92ckZ rpc]# service rpcbind start
Redirecting to /bin/systemctl start rpcbind.service
CeontOS参考:http://blog.chinaunix.net/uid-20639775-id-3399961.html
在出现如下提示的时候,注意选定“不将portmap 绑定在loopback 地址”
之后,系统会有如下提示:
Current registered services:
------------------------------------------------
100003 2 udp 2049 nfs
100003 3 udp 2049 nfs
100003 4 udp 2049 nfs
…
100003 2 tcp 2049 nfs
100003 3 tcp 2049 nfs
100003 4 tcp 2049 nfs
之后通过查看 /etc/default/portmap, 确保
#OPTIONS="-i 127.0.0.1"
前面的#号 被添加了
重启portmap服务:
$ sudo /etc/init.d/portmap restart
这样就可以了,但是要用root权限执行。
到这里所有我所遇到的问题都解决了,但是博主仍有疑问,如何实现windows和linux之间的rpc通信,这两个异构的系统如何才能建立变量传递通道,这相当困扰博主,如有好心人指点,将不胜感激。
======Below Add Time:2016-01-22=========
启动:
[root@iZ25dcp92ckZ rpc]# ./trans_server
连接:
[root@iZ25dcp92ckZ rpc]# ./trans_client
Enter File Name: /etc/hosts
127.0.0.1 iZ25dcp92ckZ Jack'sAliYunVPS jackxiang localhost
本文出自 “只争朝夕” 博客,请务必保留此出处http://xiaovfight.blog.51cto.com/1625426/398745