cygwin 中的 socket

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);
}





Supongo que te gusta

Origin blog.csdn.net/juttajry/article/details/51193355
Recomendado
Clasificación