Linux 网络编程之TCP服务器端实例(一)

TCP编程模型实例(一)

TCP客户端服务器编程模型

客户端调用序列

调用 socke t函数创建套接字
调用 connect 链接服务器端
调用 I/0 函数(read/write)与服务器端通讯
调用 close 关闭套接字

服务器端调用序列

调用 socket 函数创建套接字
调用 bind 绑定本地地址和端口
调用 listen 启动监听
调用 accept 从已连接队列中提取客户端连接
调用 I/O 函数(read/write)与客户端通讯
调用 close 关闭套接字

Linux 网络编程之TCP服务器端实例(一)_第1张图片

简单tcp服务器程序构建

实现功能,建立客户端,返回系统时间给客户端

相关函数的具体详细功能讲解请查看这篇博客.

#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h> //字节序转换需要用到的头文件
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#include <signal.h> //信号函数所需头文件
#include <time.h>	//时间函数所需头文件

int sockfd; //全局变量socket标识符

//信号函数,ctrl+c退出时关闭套接字
void sig_handler(int signo)
{
	if(signo == SIGINT) {
		printf("server close\n");
		close(sockfd);
		exit(1);
	}
}

//有客户端连接时输出客户端的地址和端口
void out_addr(struct sockaddr_in *clientaddr)
{
	//将端口从网络字节序转成主机字节序
	int port = ntohs(clientaddr->sin_port);
	char ip[16];
	memset(ip, 0, sizeof(ip));
	//将ip地址从网络字节序转换成点分十进制
	inet_ntop(AF_INET,
			&clientaddr->sin_addr.s_addr, ip, sizeof(ip));
	printf("client: %s(%d) connected\n", ip, port);
}

//向客户端发送系统时间
void do_service(int fd)
{
	long t = time(0);
	char *s = ctime(&t);
	size_t size = strlen(s) *sizeof(char);
	if(write(fd,s,size) != size) {
		perror("write error");
	}
}

int main(int argc, char *argv[])
{

	if(argc < 2) {
		printf("usage: %s #port\n", argv[0]);
		exit(1);
	}
	if(signal(SIGINT, sig_handler) == SIG_ERR) {
		perror("signal sigint error");
		exit(1);
	}

	//创建socket(套接字)
	sockfd = socket(AF_INET,SOCK_STREAM,0);

	//调用bind函数将socket和地址进行绑定
	struct sockaddr_in serveraddr;
	memset(&serveraddr,0,sizeof(serveraddr));
	//往地址中填入ip、port、internet地址族类型
	serveraddr.sin_family = AF_INET; //IPV4
	//端口格式由主机字节序转为网络字节序
	serveraddr.sin_port = htons(atoi(argv[1]));
	//特殊地址,INADDR_ANY响应所有网卡连接请求
	serveraddr.sin_addr.s_addr = INADDR_ANY;
	if(bind(sockfd, (struct sockaddr*)&serveraddr,
				sizeof(serveraddr)) < 0) { 
		perror("bind error");
		exit(1);
	}

	//调用listen函数启动监听 通知系统接受来自客户端的连接请求
	if(listen(sockfd, 10) < 0) {
		perror("listen error");
		exit(1);
	}

	//创建客户端地址结构体
	struct sockaddr_in clientaddr;
	socklen_t clientaddr_len = sizeof(clientaddr);
	while(1) {
		//调用accept函数从队列中获取一个客户端的请求连接,若没有客户端连接上来会阻塞,直到调用到客户端
		//在调用时要对地址的结构进行类型强制转换
		int fd = accept(sockfd,
				(struct sockaddr*)&clientaddr,
								&clientaddr_len);
		if(fd < 0) {
			perror("accept error");
			continue;
		}

		//调用IO函数(read/write)和连接的客户端进行双向的通讯
		out_addr(&clientaddr);
		do_service(fd);
		//关闭socket
		close(fd);
	}

	return 0;
}

编译: gcc -o tcp_test tcp_test.c

运行:./tcp_test 1554
1554 为端口号

测试1:打开浏览器输入网址http://127.0.0.1:1554/.
Linux 网络编程之TCP服务器端实例(一)_第2张图片
测试2:利用telnet连接 执行telnet ip地址 1554

ip地址为自己电脑的地址, 可以利用 ifconfig -a查看
在这里插入图片描述
我的电脑ip为192.168.19.128
执行telnet 192.168.19.128 1554
Linux 网络编程之TCP服务器端实例(一)_第3张图片

测试成功

你可能感兴趣的:(linux网络)