c中的数据流
memory中(此处的memory是cpu中的register)的数据可以来源于两个方面,一个是磁盘上的文件,另一个则是直接从用户的输入读取,当然用户输入可以直接进入文件
c中的输入输出以流的形式进行,标准的流有stdin, stdout, stderr,我们可以通过添加自己的文件流来增加输入输出的窗口,这个过程,需要将新建的流添加到descripter表中这样,我们就可以像在shell中用“<"和”>"来重定向输入和输出
重定向之后,使用fprintf和fscanf来输入输出
其实标准输入输出printf,scanf也是经过流来确定输入输出方向的
对与网络流来说,原理与重定向相同,使用socket来作为流,但是与他们不同的是socket是双向的,不能用fprintf,fscanf,而是使用send之后父进程创建新的子进程来使得多个用户连接
(processes之间的通信需要通过pipe来进行,我们通过fork来保留父进程,同时运行子进程,而不中断父进程)
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
int listener_d;
int catch_signal(int sig, void (*handler)(int) //this is how we deal with signal, signal is the way we connect program with os
{
struct sigaction action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
return sigaction (sig, &action, NULL);
}
void handle_shutdown(int sig)
{
if (listener_d)
close(listener_d);
fprintf(stderr, "Bye!\n");
exit(0);
}
void error(char *msg)
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(0); //using error means we do not need to get back, but exit
}
int read_in(int socket, char *buf, int len) //read from the client
{
char *s = buf;
int slen = len;
int c = recv(socket, s, slen, 0);
while ((c >0) && (s[c-1] != '\n'))
{
s += c;
slen -= c;
c = recv(socket, s, slen, 0);
}
if (c < 0)
return c;
else if (c == 0)
buf[0] = '\0';
else
buf[c-1] = '\0';
return len - slen;
}
int say(int socket, char *s) //send info to the server
{
int result = send(socket, s, strlen(s), 0);
if (result == -1)
fprintf(stderr, "%s, %s\n", "error talking to the client", strerror(errno));
return result;
}
int main(int argc, char *argv[])
{
if (catch_signal(SIGINT, handle_shutdown) == -1)
error("cannot set the interrrpt handler");
listener_d = socket(PF_INET, SOCK_STREAM, 0);//make a parent socket, which is just like a stream as file and io stream
//and we give it a new descripter
if (listener_d == -1)
error("cannot open socket");
struct sockaddr_in name;
name.sin_family = PF_INET;
name.sin_port = (in_port_t)htons(30000);
name.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(listener_d, (struct sockaddr *)&name, sizeof(name)) == -1)//we bind the socket to the port
error("cannot bind to port");
int reuse = 1;
if (setsockopt(listener_d, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(int)) == -1)
error("cannot set the reuse option on the socket");
if(listen(listener_d, 10) == -1)
error("cannot listen");
puts("waiting");
while (1){
struct sockaddr_storage client_addr;
unsigned int address_size = sizeof(client_addr);
int connect_d = accept(listener_d, (struct sockaddr *)&client_addr, &address_size);//we don't use parent socket
//we create children sockets to deal with asks at the same time
if (connect_d == -1)
error("cannot open secondary socket");
if (!fork()) //in order to create new process, we need to fork (copy) the parent process
{
close(listener_d); //now the child socket is indepandent, where we open the parent socket again???
char buf[100];
say(connect_d, "Internet Knock-knock protocol server \r\nversion 1\r\nknocknock\r\n>");
read_in(connect_d, buf, sizeof(buf));
say(connect_d, "who is jinruoyan\r\n");
read_in(connect_d, buf, sizeof(buf));
say(connect_d, "where is she\r\n");
close(connect_d);
exit(0);
}
//close(connect_d); why need this
}
return 0;
}
以上的代码是建立server的过程,我们通过Cywin中的telnet来连接这个server,即localhost
而连接web server是同样的道理,我们需要建立socket来创建数据流,来从web server获得数据,不过我们需要遵循protocol,来使得请求发送成功,并且获得类型一致的server的回应
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
void error(char *msg)
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(0);
}
int open_socket(char *host, char *port)
{
struct addrinfo *res;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(host, port, &hints, &res) == -1)
error("cannot resolve the address");
int d_sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (d_sock == -1)
error("cannot open socet");
if (connect(d_sock, res->ai_addr, res->ai_addrlen) == -1)
error("cannot connect to socket");
return 0;
}
int say(int socket, char *s)
{
int result = send(socket, s, strlen(s), 0);
if (result == -1)
fprintf(stderr, "%s, %s\n", "error talking to the server", strerror(errno));
return result;
}
int main(int argc, char *argv[])
{
int d_sock;
d_sock = open_socket("cn.baidu.com", "80");//we open a socket to get info from the Internet
if (d_sock == -1)
error("cannot open a socket");
char buf[] = "GET /baidu http/1.1\r\n";
//sprintf(buf,"GET/wiki/%s http/1.1\r\n", argv[1]);
say(d_sock, buf);//we tell the web server to what we want, since this port is a two-way port
say(d_sock, "Host: cn.baidu.com"); //we get the info from the internet web server
char rec[256];
int bytesRcvd = recv(d_sock, rec, 255, 0);
while (bytesRcvd)
{
if (bytesRcvd == -1)
error("cannot read from the server");
rec[bytesRcvd] = '\0';
printf("%s", rec);
bytesRcvd = recv(d_sock, rec, 255, 0);
}
close(d_sock);
}