码迷,mamicode.com
首页 > 其他好文 > 详细

服务器、客户端简单交互程序

时间:2015-04-11 09:01:48      阅读:86      评论:0      收藏:0      [点我收藏+]

标签:网络编程   服务器客户端   服务器客户端交互   server   client   

        这是一个简单的TCP服务器/客户端的程序示例。客户端发送两个long型变量到服务器端,服务器端读取这两个long型变量并返回这两个变量的和给客户端。

这是服务器端的示例代码:

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

#define MAXLINE 1024
#define LISTENQ 5

void str_echo(int connfd);
void sig_chld(int sign);
void err_sys(char *str);

int main(void)
{
	int listenfd, connfd;
	pid_t childpid;
	socklen_t clilen;
	struct sockaddr_in servaddr, cliaddr;

	if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		err_sys("socket error");

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(4321); //4321端口是自己填写的临时端口,只要和客户端上填写的服务器端口是该临时端口就可以了
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
		err_sys("bind error");
	if(listen(listenfd, LISTENQ) < 0)
		err_sys("listen error");

	signal(SIGCHLD, sig_chld);

	for( ; ; )
	{
		clilen = sizeof(cliaddr);
		if((connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen)) < 0)
		{
			//if(errno == EINTR)	//如果在Linux下的vim编写的话可以把这三行注释到的代码给加上去
			//	continue;
			//else
				err_sys("accept error");
		}

		if((childpid = fork()) == 0)
		{
			printf("I am in child %d\n", getpid());
			close(listenfd);
			str_echo(connfd);
			close(connfd);
			exit(0);
		}
		close(connfd);
	}

	return 0;
}

/*
* the function to handle INT of SIGCHLD
*/
void sig_chld(int sign)
{
	pid_t pid;
	int stat;

	while((pid = waitpid(-1, &stat, WNOHANG)) > 0)
		printf("child %d terminated\n", pid);

	return;
}

/*
* send the sum of two long numbers to client
*/
void str_echo(int sockfd)
{
	long arg1, arg2;
	ssize_t n;
	char line[MAXLINE];

	for( ; ; )
	{
		if((n = read(sockfd, line, MAXLINE)) == 0)
			return;
		if(sscanf(line, "%ld%ld", &arg1, &arg2) == 2)
			snprintf(line, sizeof(line), "%ld\n", arg1 + arg2);
		else
			snprintf(line, sizeof(line), "input error");
		n = strlen(line);
		if(write(sockfd, line, n) != n)
			err_sys("write error");
	}
}

void err_sys(char *str)
{
    perror(str);
    exit(1);
}

以下是客户端的示例代码

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

#define MAXLINE 1024

void str_cli(int sockfd);
void err_sys(char *str);

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

	if(argc != 2)
	{
		printf("usage: ./a.out <ip>\n");
		exit(1);
	}
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		err_sys("socket error");

	printf("sockfd is ok\n");
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(4321);
	if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) < 0)
		err_sys("inet_pton error");

	if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
		err_sys("connect error");

	printf("connect is ok\n");
	str_cli(sockfd);

	close(sockfd);

	return 0;
}

/*
* send two long num to server host
*/
void str_cli(int sockfd)
{
	char sendline[MAXLINE], recvline[MAXLINE];

	while(fgets(sendline, MAXLINE, stdin) != NULL)
	{
		if(write(sockfd, sendline, strlen(sendline)) < 0)
            err_sys("write error");
		if(read(sockfd, recvline, MAXLINE) == 0)
			err_sys("read error");
		fputs(recvline, stdout);
		bzero(recvline, strlen(recvline));
	}
}

void err_sys(char *str)
{
    perror(str);
    exit(1);
}


基本套接字函数讲解

socket函数

#include <sys/socket.h>
int socket(int family, int type, int protocol);  //成功返回非负描述符,出错返回-1
          socket函数指定期望的通信协议类型(使用IPv4的TCP、使用IPv6的UDP、Unix域字节流协议)和套接字字类型(字节流、数据报或原始套接字)

----socket函数的family常值 ---------------

family             说明                         
AF_INET       IPv4协议             
AF_INET6     IPv4协议            
AF_LOCAL   Unix协议域      
AF_ROUTE   路由套接字     
AF_KEY         秘钥套接字         
----------------------------------------------------

----socket函数的type常值 ------------------

SOCK_STREAM           字节流套接字

SOCK_DGRAM            数据报套接字

SOCK_SEQPACKET  有序分组套接字

SOCK_RAW                 原始套接字

----------------------------------------------------

----socket函数的protocal常值 ------------

IPPROTO_CP        TCP传输协议

IPPROTO_UDP     UDP传输协议

IPPROTO_SCTP   SCTP传输协议

----------------------------------------------------

connect函数

#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);  //成功返回0,出错为-1
        TCP客户用connect函数来建立一个与TCP服务器连接,sockfd是由socket函数返回的套接字描述符,第二个、第三个参数分别是指向一个套接字地址结构的指针和该结构的大小,套接字结构必须含有服务器的IP地址和端口号。如果connect失败后,就必须close当前的套接字描述符并重新调用socket。
bind函数

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);  //成功返回0,出错-1

        bind函数把一个本地协议地址赋予一个套接字,它只是把一个协议地址赋予一个套接字,至于协议地址的含义则取决于协议本身。第二个参数指向协议地址结构的指针,第三个参数是协议地址的长度,对于TCP,调用bind函数可以指定一个端口号,或指定一个IP地址,或两者都指定,也可以两者都不指定。

listen函数

#include <sys/socket.h>
int listen(int sockfd, int backlog);  //成功返回0,出错-1
        socket创建一个套接字时,它被假设为一个主动套接字,也就是说,它是一个将调用connect发起连接的一个客户套接字。listen函数把一个未连接的套接字转换为一个被动套接字,指示内核应接受指向该套接字的连接请求,调用listen函数将导致套接字从CLOSEE状态转换到LISTEN状态。第二个参数规定了内核应为相应套接字排队的最大连接个数。
(1)、未完成连接队列:每一个这样的SYN分节对应其中一项:已由某个客户发出并到达服务器,而服务器正在等待完成相应的TCP三路握手过程。这些套接字处于SYN_RCVD状态。

(2)、已完成连接队列:每个完成TCP三路握手过程的客户对应其中一项,这些套接字处于ESTABLISHED状态。

------------------------------------------------------------------------------------------------------------------------------------------------------

TCP监听套接字维护的两个队列

技术分享

技术分享

accept函数

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);  //成功返回非负描述符,出错返回-1
       如果accept成功,那么其返回值是由内核自动生成的一个全新套接字,代表与返回客户的TCP连接,函数的第一个参数为监听套接字,返回值为已连接套接字。


------------------------------------------------------------------------------------------------------------------------------------------------------

服务器、客户端程序流程图

技术分享


------------------------------------------------------------------------------------------------------------------------------------------------------

TCP状态转换图

技术分享


------------------------------------------------------------------------------------------------------------------------------------------------------

参考资料:

1、《UNIX网络编程 卷1 套接字联网API》 第四章-基本套接字编程

2、《计算机网络 - 谢希仁》


服务器、客户端简单交互程序

标签:网络编程   服务器客户端   服务器客户端交互   server   client   

原文地址:http://blog.csdn.net/u012796139/article/details/44984879

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!