【十二】进程间通信——[BSD]套接字(socket)

【十二】 进程间通信——[BSD]套接字(socket)

/*sever.c*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define N 64
#define R 1
#define B 2
#define U 3
#define E 4

typedef struct
{
	int type;
	char name[16];
	char text[N];
} MSG;

typedef struct _node_
{
	struct sockaddr_in cliaddr;
	struct _node_ *next;
} linknode, *linklist;

typedef struct sockaddr SA;

void AddUser(int sockfd, MSG buf, struct sockaddr_in peeraddr, linklist h)
{
	linklist p;

	p = (linklist)malloc(sizeof(linknode));
	p->cliaddr = peeraddr;
	p->next = h->next;
	h->next = p;
	sprintf(buf.text, "%s is online\n", buf.name);
	strcpy(buf.name, "system");
	p = p->next;
	while (p != NULL)
	{
		sendto(sockfd, &buf, sizeof(buf), 0, (SA *)&p->cliaddr, sizeof(peeraddr));
		p = p->next;
	}
	strcpy(buf.text, "Welcome To Farsight Chat Room\n");
	sendto(sockfd, &buf, sizeof(buf), 0, (SA *)&peeraddr, sizeof(peeraddr));

	return;
}

void DelUser(int sockfd, MSG buf, struct sockaddr_in peeraddr, linklist h)
{
	linklist p = h->next;

	sprintf(buf.text, "%s is offline\n", buf.name);
	strcpy(buf.name, "system");

	while (p != NULL)
	{
		if (memcmp(&peeraddr, &p->cliaddr, sizeof(peeraddr)) == 0)
		{
			h->next = p->next;
			free(p);
		}
		else
		{
			sendto(sockfd, &buf, sizeof(buf), 0, (SA *)&p->cliaddr, sizeof(peeraddr));
			h = h->next;
		}
		p = h->next;
	}
	strcpy(buf.text, "See You Next Time\n");
	sendto(sockfd, &buf, sizeof(buf), 0, (SA *)&peeraddr, sizeof(peeraddr));

	return;
}

void Broadcast(int sockfd, MSG buf, linklist h)
{
	h = h->next;
	while (h != NULL)
	{
		sendto(sockfd, &buf, sizeof(buf), 0, (SA *)&h->cliaddr, sizeof(h->cliaddr));
		h = h->next;
	}

	return;
}

int main(int argc, char *argv[])
{
	int sockfd;
	struct sockaddr_in myaddr, peeraddr;
	socklen_t peerlen;
	MSG buf;
	pid_t pid;

	if (argc < 3)
	{
		printf("Usage : %s <ip> <port>\n", argv[0]);
		exit(-1);
	}

	// XXX int socket(int domain, int type, int protocol);
	if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
	{
		perror("fail to socket");
		exit(-1);
	}

	// XXX int bind(int sockfd, const struct sockaddr *addr,
	//              socklen_t addrlen);
	bzero(&myaddr, sizeof(myaddr));
	myaddr.sin_family = PF_INET;
	myaddr.sin_port = htons(atoi(argv[2]));
	myaddr.sin_addr.s_addr = inet_addr(argv[1]);
	if (bind(sockfd, (SA *)&myaddr, sizeof(myaddr)) < 0)
	{
		perror("fail to bind");
		exit(-1);
	}

	if ((pid = fork()) < 0)
	{
		perror("fail to fork");
		exit(-1);
	}
	else if (pid == 0)  // dispatch message
	{
		linklist h = (linklist)malloc(sizeof(linknode));
		h->next = NULL;
		peerlen = sizeof(peeraddr);
		while ( 1 )
		{
			recvfrom(sockfd, &buf, sizeof(buf), 0, (SA *)&peeraddr, &peerlen);
			switch ( buf.type )
			{
			case R :
				AddUser(sockfd, buf, peeraddr, h);
				break;
			case U :
				DelUser(sockfd, buf, peeraddr, h);
				break;
			case B :
			case E :
				Broadcast(sockfd, buf, h);
				break;
			}
		}
	}
	else  // send message
	{
		strcpy(buf.name, "system");
		buf.type = B;
		while ( 1 )
		{
			printf("server > ");
			fgets(buf.text, N, stdin);
			if (strncmp(buf.text, "quit\n", 5) == 0) break;
			sendto(sockfd, &buf, sizeof(buf), 0, (SA *)&myaddr, sizeof(myaddr));
			usleep(100000);
		}
		buf.type = E;
		sendto(sockfd, &buf, sizeof(buf), 0, (SA *)&myaddr, sizeof(myaddr));
		usleep(100000);
		kill(pid, SIGUSR1);
		exit(0);
	}
	
	return 0;
}

/*client.c*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define N 64
#define R 1
#define B 2
#define U 3
#define E 4

typedef struct
{
	int type;
	char name[16];
	char text[N];
} MSG;

typedef struct sockaddr SA;

int main(int argc, char *argv[])
{
	int sockfd;
	struct sockaddr_in servaddr;
	MSG buf;
	pid_t pid;

	if (argc < 3)
	{
		printf("Usage : %s <ip> <port>\n", argv[0]);
		exit(-1);
	}

	printf("please input your name : ");
	fgets(buf.name, 16, stdin);
	buf.name[strlen(buf.name)-1] = '\0';

	// XXX int socket(int domain, int type, int protocol);
	if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
	{
		perror("fail to socket");
		exit(-1);
	}

	// XXX int bind(int sockfd, const struct sockaddr *addr,
	//              socklen_t addrlen);
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = PF_INET;
	servaddr.sin_port = htons(atoi(argv[2]));
	servaddr.sin_addr.s_addr = inet_addr(argv[1]);

	buf.type = R;
	sendto(sockfd, &buf, sizeof(buf), 0, (SA *)&servaddr, sizeof(servaddr));  // register

	if ((pid = fork()) < 0)
	{
		perror("fail to fork");
		exit(-1);
	}
	else if (pid == 0)  // recv message
	{
		while ( 1 )
		{
			recvfrom(sockfd, &buf, sizeof(buf), 0, NULL, NULL);
			if (buf.type == E) break;
			printf("\n *** [%s] %s", buf.name, buf.text);
		}
		printf("Server is down, exit...\n");
		kill(getppid(), SIGUSR1);
		exit(0);
	}
	else  // send message
	{
		buf.type = B;
		while ( 1 )
		{
			printf("client > ");
			fgets(buf.text, N, stdin);
			if (strncmp(buf.text, "quit\n", 5) == 0) break;
			sendto(sockfd, &buf, sizeof(buf), 0, (SA *)&servaddr, sizeof(servaddr));
			usleep(100000);
		}
		buf.type = U;
		sendto(sockfd, &buf, sizeof(buf), 0, (SA *)&servaddr, sizeof(servaddr));
		usleep(100000);
		kill(pid, SIGUSR1);
		exit(0);
	}
	
	return 0;
}


你可能感兴趣的:(【十二】进程间通信——[BSD]套接字(socket))