A. linux下的 socket编程问题!
第一个问题:
对,是那样的,用open打开文件,用read读取文件,在发送给对方,接收方接收到后,写入文件就可以了。不过在这个过程中最好别用字符串函数,除非你很熟悉。
第二个问题
首先你得去搞清楚什么是线程,什么是进程,fork出来的叫进程,pthread_create出来的才叫线程。服务器有很多种模型(多进程,多线程,select,epoll模型,这个我的blog上有,famdestiny.cublog.cn),不一定要用多进程。
给你写了个代码,自己先看看:
注意,在自己的目录下创建一个叫pserverb的文件,程序会把这个文件复制成test文件。你可以自己根据需要改改
server:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define SERV_PORT 5358
#define MAX_CONN 10
#define BUF_LEN 1024
void str_echo(FILE *fp, int sockfd){
ssize_t nread;
int file_fd;
char buf[BUF_LEN] = {0};
file_fd = open("test", O_WRONLY | O_TRUNC | O_CREAT, 0755);
while(1) {
bzero(buf, BUF_LEN);
if((nread = read(sockfd, buf, BUF_LEN)) == -1) {
if(errno == EINTR) {
continue;
}
else {
printf("readn error: %s\n", strerror(errno));
continue;
}
}
else if (nread == 0) {
break;
}
else {
printf("%s\n", buf);
write(file_fd, buf, nread);
}
}
close(file_fd);
}
void sig_chld(int sig){
pid_t pid;
int state;
while((pid = waitpid(-1, &state, WNOHANG)) > 0){
printf("child process %d exited.", pid);
}
return;
}
int main(int argc, char **argv)
{
int listenfd, connfd;
socklen_t cliaddrlen;
pid_t childpid;
struct sockaddr_in servaddr, cliaddr;
if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
printf("socket error: %s\n", strerror(errno));
return 0;
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1){
printf("bind error: %s\n", strerror(errno));
return 0;
}
if(listen(listenfd, MAX_CONN) == -1){
printf("listen error: %s\n", strerror(errno));
return 0;
}
signal(SIGCHLD, sig_chld);
while(1){
cliaddrlen = sizeof(cliaddr);
if((connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddrlen)) == -1){
if(errno == EINTR){
continue;
}
else{
printf("accept error: %s\n", strerror(errno));
continue;
}
}
if((childpid = fork()) == 0){
close(listenfd);
str_echo(stdin, connfd);
exit(0);
}
else if(childpid > 0){
close(connfd);
}
else{
printf("fork error!\n");
continue;
}
}
}
client:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#define SERV_ADDR "127.0.0.1"
#define SERV_PORT 5358
#define BUF_LEN 1024
void str_cli(char *path, int sockfd)
{
char sendbuf[BUF_LEN] = {0};
int fd, n;
if((fd = open("./pserverb", O_RDONLY)) == -1){
printf("%s\n", strerror(errno));
exit(0);
}
while((n = read(fd, sendbuf, BUF_LEN)) != 0) {
if(n < 0){
printf("%s\n", strerror(errno));
exit(0);
}
write(sockfd, sendbuf, n);
bzero(sendbuf, BUF_LEN);
}
close(fd);
return;
}
int main(int argc, char **argv)
{
int fd;
struct sockaddr_in servaddr;
fd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(SERV_ADDR);
servaddr.sin_port = htons(SERV_PORT);
if (connect(fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
printf("connect error: %s\n", strerror(errno));
return 0;
}
str_cli(argv[1], fd);
return 0;
}
B. 如何在linux中编写一个类似CreateProcess的函数
CreateProcess函数可以创建一个新的进程并调用一个外部程序
并且它有很多参数可以设置新的进程相关的状态
如果只要想简单地完成创建一个进程并调用一个外部程序的话
在linux上可以使用fork或者clone来进行创建进程
然后使用exec族函数来调用一个外部程序
一个简单的实现大概是这样的
intcreate_procress(constchar*path,constchar*name,constchar*arg)
{
pid_tpid;
pid=fork();
if(pid==0)
{
if(execl(path,name,arg,NULL)==-1)
{
perror(path);
_exit(-1);
}
}
elseif(pid==-1)
return-1;
return0;
}
参数path为执行外部程序的路径
name为运行程序的名称(argv[0])
arg为命令行参数(从argv[1]开始)
如果对新进程有其它需求的话比如设置环境变量等可以使用execle等进行扩展
或者其它的要求也可以使用linux提供的相应api在fork后进行设置
C. 下面是我在linux下写的守护进程,现在想收到SIGUSR1的信号后跳出while循环,该怎么写
守护进程只知道抄过程,没具体实现过,但我想了想,你可以设置一个变量,给变量一个初值比如count = 1;然后while(count),然后你收到SIGUSR1后去执行特定函数,把count置零,这样就可以实现。 然后再一个if语句,判count是否为0,为0就break,这样就达到目的了,俺不是牛人,就想到了这个办法,有好办法分享一下哈。。。
D. 如何在Linux下实现client和server的互传
就是一个TCP通信的过程嘛,可以参考如下程序源码,望采纳!另外,可以找一些linux网络编程的资料看看。
/* tcpcli.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define DEFAULT_PORT 8800
int main(int argc, char** argv)
{
int cPort = DEFAULT_PORT;
int cClient = 0;
int cLen = 0;
struct sockaddr_in cli;
char cbuf[4096] = {0};
if(argc < 2)
{
printf("Uasge: client[server IP address]\n");
return -1;
}
memset(cbuf, 0, sizeof(cbuf));
cli.sin_family = AF_INET;
cli.sin_port = htons(cPort);
cli.sin_addr.s_addr = inet_addr(argv[1]);
cClient = socket(AF_INET, SOCK_STREAM, 0);
if(cClient < 0)
{
printf("socket() failure!\n");
return -1;
}
if(connect(cClient, (struct sockaddr*)&cli, sizeof(cli)) < 0)
{
printf("connect() failure!\n");
return -1;
}
cLen = recv(cClient, cbuf, sizeof(cbuf),0);
if((cLen < 0)||(cLen == 0))
{
printf("recv() failure!\n");
return -1;
}
printf("recv() Data From Server: [%s]\n", cbuf);
close(cClient);
return 0;
}
编译代码:gcc -o tcp_clt client_tcp.c
执行命令:./tcp_clt 192.168.0.230
TCP scoket服务端程序代码
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include<sys/wait.h>
#include <string.h>
/*********************************************************************
*filename: tcpserver.c
*purpose:tcp服务端程序
********************************************************************/
int main(int argc, char ** argv)
{
int sockfd,new_fd; /* 监听socket: sock_fd,数据传输socket: new_fd */
struct sockaddr_in my_addr; /* 本机地址信息 */
struct sockaddr_in their_addr; /* 客户地址信息 */
unsigned int sin_size, myport, lisnum;
if(argv[1]) myport = atoi(argv[1]);
else myport = 8800;
if(argv[2]) lisnum = atoi(argv[2]);
else lisnum = 2;
if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
printf("socket %d ok \n",myport);
my_addr.sin_family=PF_INET;
my_addr.sin_port=htons(myport);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero), 0);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}
printf("bind ok \n");
if (listen(sockfd, lisnum) == -1) {
perror("listen");
exit(1);
}
printf("listen ok \n");
/*
while(1) {
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
perror("accept");
continue;
}
printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
if (!fork()) { //子进程代码段
if (send(new_fd, "Hello, world!\n", 14, 0) == -1) {
perror("send");
close(new_fd);
exit(0);
}
}
close(new_fd); //父进程不再需要该socket
waitpid(-1,NULL,WNOHANG);//等待子进程结束,清除子进程所占用资源
}
*/
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
perror("accept");
exit(0);
}
printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
int step = 0;
while(1) {
char szSnd[63] = {0};
sprintf(szSnd,"i am server [%d]\n",step);
step++;
if (send(new_fd, szSnd, strlen(szSnd), 0) == -1) {
perror("send");
close(new_fd);
break;
}
printf("send msg: %s \n",szSnd);
sleep(1);
}
exit(0);
}
}
编译指令:gcc -o tcp_srv tcpserver.c
执行服务器端程序:./tcp_srv
创建成功,绑定端口成功,监听成功后,循环发送i am server字符串。
E. linux里面的wait和waitpid是什么
wait和waitpid的不同在于wait会令调用者阻塞直至某个子进程终止而waitpid则可以通过设置一个选项来设置为非阻塞,另外waitpid并不是等待第一个结束的进程而是等待参数中pid指定的进程。
waitpid提供了wait所没有的三个特性:
1 waitpid使我们可以等待指定的进程
2 waitpid提供了一个无阻塞的wait
3 waitpid支持工作控制
具体可以查看APUE page202
F. linux下C语言socket编程双机互发数据
这个问题很好办啦,服务器接受一个连接请求,然后开一个线程或者进程都可以,再在线程或者进程里面采用其他技术实现同时收发(比如I/O复用,比如非阻塞I/O)。客户端也可以采用I/O复用。
推荐资料的话,《unix网络编程》这本书很好,公认的经典,当教科书用,这本书里有你想要的所有内容。
ps:你基础太差,多补补吧,别想一下吃个胖子。
另外我这里正好有个例子满足你的要求,贴给你,自己写的,不是网上找的,用的是多进程加I/O复用技术:
server端:
/****************************************************************
**
**
**
****************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#define BUFLEN 1024
#define MAX(a,b) ((a)>(b)?(a):(b))
typedef void Sigfunc (int);
void str_echo(FILE *,int);
//Sigfunc *signal(int, Sigfunc *);
int main(int argc,char **argv)
{
int connfd,listenfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr,servaddr;
void sig_chld(int);
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(5358);
bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
listen(listenfd,8);
signal(SIGCHLD,sig_chld);
while(1)
{
clilen = sizeof(cliaddr);
if((connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&clilen)) < 0)
{
if(errno == EINTR)
{
fputs("accept error: EINTR\n",stdout);
continue;
}
else
{
fputs("accept error..\n",stdout);
}
}
if((childpid = fork()) == 0)
{
close(listenfd);
str_echo(stdin,connfd);
exit(0);
}
close(connfd);
}
}
void str_echo(FILE *fp,int sockfd)
{
int n = 0;
char sendbuf[BUFLEN] = { 0 },recvbuf[BUFLEN] = { 0 };
int maxfdp;
fd_set rset;
FD_ZERO(&rset);
while(1)
{
FD_SET(fileno(fp),&rset);
FD_SET(sockfd, &rset);
maxfdp = MAX(fileno(fp),sockfd)+1;
select(maxfdp, &rset ,NULL, NULL, NULL);
if(FD_ISSET(sockfd, &rset))
{
if(n = read(sockfd, recvbuf, BUFLEN) == 0)
{
return;
}
if(n == -1)
{
break;
}
printf("%s\n",recvbuf);
memset(recvbuf,0,BUFLEN);
}
if(FD_ISSET(fileno(fp),&rset))
{
scanf("%s",sendbuf);
write(sockfd, sendbuf,strlen(sendbuf));
}
}
}
void sig_chld (int signo)
{
pid_t pid;
int stat;
while ((pid = waitpid(-1,&stat, WNOHANG)) > 0)
{
printf("child %d terminated\n",pid);
}
return;
}
client端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#define MAX(a,b) (a)>(b)?(a):(b)
int main()
{
int s,connectReturn, maxfd;
fd_set rset;
char sendbuf[1024] = {0};
char recvbuf[1024] = {0};
long port=5358;
s=socket(PF_INET,SOCK_STREAM,0);
struct sockaddr_in sa;
sa.sin_family=AF_INET;
sa.sin_addr.s_addr=inet_addr("127.0.0.1");
sa.sin_port=htons(port);
connectReturn=connect(s,(struct sockaddr *)&sa,sizeof(sa));
printf("%d\n",connectReturn);
FD_ZERO(&rset);
while(1)
{
FD_SET(fileno(stdin), &rset);
FD_SET(s, &rset);
maxfd=MAX(fileno(stdin), s) + 1;
select(maxfd, &rset, NULL, NULL, NULL);
if(FD_ISSET(fileno(stdin), &rset))
{
scanf("%s",sendbuf);
send(s,sendbuf,strlen(sendbuf),0);
bzero(sendbuf, 1024);
}
else if(FD_ISSET(s, &rset))
{
memset(recvbuf,0,1024);
recv(s,recvbuf,1024,0);
printf("remote: %s\n",recvbuf);
}
}
return 0;
}
G. linux下system函数调用shell命令后,怎样让主进程等子进程返回后,接着执行
这是进程间同步的问题。解决方法是:fork一个子进程执行system调用,父进程调用 wait 或 waitpid 等待子进程的终止信息。
父进程调用 wait 或 waitpid 时可能会:
• 阻塞(如果它的所有子进程都还在运行)。
• 带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信息)。
• 出错立即返回(如果它没有任何子进程)。
wait 和 waitpid 这两个函数的区别是:
• 如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而调用waitpid时如果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。
• wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程。