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參數指定等待哪一個子進程。