TCP网络程序设计

基于TCP---通讯模型

TCP网络程序设计_第1张图片

由上图可以得出TCP通讯的步骤如下:

服务端:

1、创建一个socket,用函数socket();
2、绑定IP地址、端口等信息到socket上,用函数bind();
3、设置允许的最大连接数,用函数listen();
4、等待来着客户端的连接请求,用函数accept();
5、收发数据,用函数send()和recv(),或者read()和write();
6、关闭网络连接;


客户端:

1、创建一个socket,用函数socket;
2、设置要连接的服务器的IP地址和端口等属性;
3、连接服务器,用函数connect();
4、收发数据,用函数send()和recv(),或者read()和write();
5、关闭网络连接;


示例程序如下:

服务端:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>

#define PROT_NUMBER		3333
#define LINK_NUMBER		20
#define BUF_SIZE		1024
int main(int argc, char *argv[]){
	
	int server_fd, new_sockfd, sin_size;
	struct sockaddr_in server_addr,client_addr;
	char buf[BUF_SIZE] = {0};

	bzero(&server_addr, sizeof(struct sockaddr_in));
	bzero(&client_addr, sizeof(struct sockaddr_in));
	//创建socket套结字
	server_fd = socket(AF_INET,SOCK_STREAM,0);/*AF_INET:IPv4;SOCKET_STREAM: TCP*/
	if(server_fd == -1){
		fprintf(stderr, "Socket Error %s\n\a", strerror(errno));
		exit(EXIT_FAILURE);
	}
	//填充socket套结字
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(PROT_NUMBER);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	//绑定套结字
	if((bind(server_fd, (struct sockaddr *)(&server_addr),sizeof(struct sockaddr_in))) == -1){
		fprintf(stderr, "Bind Error %s\n\a", strerror(errno));
		exit(EXIT_FAILURE);
	}
	
	//设置最大连接数
	if((listen(server_fd, LINK_NUMBER)) == -1){
		fprintf(stderr, "Listen Error %s\n\a", strerror(errno));
		exit(EXIT_FAILURE);
	}

	
		sin_size = sizeof(struct sockaddr_in);
		//服务器阻塞,等待客户端链接
		if((new_sockfd = accept(server_fd,(struct sockaddr *)(&client_addr),&sin_size)) == -1){
			fprintf(stderr, "Accept Error %s\n\a", strerror(errno));
			exit(EXIT_FAILURE);
		}
		fprintf(stdout,"Server get connection from %s\n",inet_ntoa(client_addr.sin_addr));
	while(1){
		//接收客户端发送的内容
		if((recv(new_sockfd,buf,BUF_SIZE,0)) == -1){
			fprintf(stderr, "Recv Error %s\n\a", strerror(errno));
			exit(EXIT_FAILURE);
		}
		else if(*buf == '\0'){
			break;
		}
		
		printf("Server received %s\n",buf);
		bzero(&buf,BUF_SIZE);
	}

	close(server_fd);

	return 0;
}

客户端:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>

#define SERVER_PORT			3333
#define BUF_SIZE			1024

int main(int argc, char *argv[]){
	if(argc != 2){
		printf("Usage: %s hostname\n",argv[0]);
		exit(EXIT_FAILURE);
	}

	int client_fd;
	struct sockaddr_in server_addr;
	struct hostent *host;
	char buf[BUF_SIZE] = {0};

	bzero(&server_addr,sizeof(struct sockaddr_in));

	//通过域名得到IP
	if((host = gethostbyname(argv[1])) == NULL){
		switch(h_errno)  
        	{  
           	 case HOST_NOT_FOUND :  
				 printf("The specified host is unknown\n");  
               	 break;  
  
             case NO_ADDRESS:  
                 printf("The requested name is valid but does not have an IP address.\n");  
                 break;  
  
             case NO_RECOVERY:  
                 printf(" A nonrecoverable name server error occurred.\n");  
                 break;  
  
             case TRY_AGAIN:  
                 printf("A temporary error occurred in the authoritative \
						 domain name server. Please try again later.\n");  
                 break;  
        	}
		exit(EXIT_FAILURE);
	}

	//创建套结字
	client_fd = socket(AF_INET, SOCK_STREAM , 0);
	if(client_fd == -1){
		fprintf(stderr,"Socket error:%s",strerror(errno));
		exit(EXIT_FAILURE);
	}

	//填充服务端sockaddr结构
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(SERVER_PORT);
	server_addr.sin_addr = *((struct in_addr*)host->h_addr);
	
	//连接服务器
	if((connect(client_fd, (struct sockaddr *)(&server_addr),sizeof(struct sockaddr_in))) == -1){
		fprintf(stderr,"Connect error:%s",strerror(errno));
		exit(EXIT_FAILURE);
	}

	while(1){
		scanf("%s",buf);
		if(strcmp(buf,"Quit") == 0){
			break;
		}
	//发送数据
		if((send(client_fd,buf,sizeof(buf),0)) == -1){
			fprintf(stderr,"Connect error:%s",strerror(errno));
			exit(EXIT_FAILURE);
		}
	}

	close(client_fd);
}


总结:

1、填充sockaddr结构体时,注意字节序;

2、服务端的阻塞位置 accept (等待客户端) recv (接收时的阻塞);


你可能感兴趣的:(TCP网络程序设计)