Linux下socket编程之TCP简单实现

本文主要是简单的实现一个Linux下TCP网络编程的小例子。总共分为两个部分:客服端的实现和服务器端的实现。实现的功能很简单,当客服端和服务器端绑定之后,通过在客服端输入一个字符串,服务器将客服端输入的字符串进行相应的输出。

一、服务器端的实现

1、打开一个socket设备,获得socket设备的文件描述符,指定网络协议和传输类型

/* 1、获得服务器端的socket文件描述符 */
iSocketServerFd = socket(AF_INET, SOCK_STREAM, 0);	// 网络协议是ipv4,传输方式为tcp
if(iSocketServerFd == -1)
{
	printf("socket error!\n");
	return -1;
}
2、绑定

主要是将第一步获得的文件描述符与具体的服务器端进行绑定,包括网络的协议、端口号、对客服端的访问限制等。

/* 2、对服务器端进行绑定 */
/* 2.1 设置服务器端的socket地址描述结构体 */
tSocketServerAddr.sin_family      = AF_INET;			// 网络协议是ipv4
tSocketServerAddr.sin_port        = htons(SOCKET_PORT);	// socket的端口号
tSocketServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);	// 客服端的地址可以是任意的
memset(tSocketServerAddr.sin_zero, 0, 8);

iSockAddrLen = sizeof(struct sockaddr);	// 获得这个结构体的大小
/* 2.2 绑定 */
iRet = bind(iSocketServerFd, (const struct sockaddr *)&tSocketServerAddr, iSockAddrLen);
if(iRet == -1)
{
	printf("bind error!\n");
	return -1;
}
3、监听

对客服端进行监听。

/* 3、服务器端进行监听 */
iRet = listen(iSocketServerFd, LISTEN_BACKLOG);
if(iRet == -1)
{
	printf("listen error!\n");
	return -1;
}
4、accept

/* 4、接收一个客服端的socket的连接 */
iSocketClientFd = accept(iSocketServerFd, (struct sockaddr *)&tSocketClientAddr, &iSockAddrLen);
if(iSocketClientFd < 0)
{
	printf("accept error!\n");
	return -1;
}
5、接收和发送数据

/* 接收从客服端传送过来的数据 */
iRecvLen = recv(iSocketClientFd, ucRecvBuf, ARRAY_LENGTH, 0);

服务器端的完整实现代码如下:
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>

#define SOCKET_PORT		1234	// 定义端口,与指定的socket绑定
#define LISTEN_BACKLOG	10		// 最大监听的客服端数量
#define ARRAY_LENGTH	256		// 接收缓冲区的大小

/* 程序的入口函数 */
int main(void)
{
	int iSocketServerFd;	// 定义服务器的文件描述符
	int iSocketClientFd;	// 定义客服端的文件描述符

	struct sockaddr_in tSocketServerAddr;	// 服务器socket地址的描述结构体定义
	struct sockaddr_in tSocketClientAddr;	// 客服端socket地址的描述结构体定义

	int iSockAddrLen;
	int iRet;

	unsigned char ucRecvBuf[ARRAY_LENGTH];	// 定义接收数据的缓冲区
	int iRecvLen;

	int client_flag = 0;

	signal(SIGCHLD,SIG_IGN); 

	/* 1、获得服务器端的socket文件描述符 */
	iSocketServerFd = socket(AF_INET, SOCK_STREAM, 0);	// 网络协议是ipv4,传输方式为tcp
	if(iSocketServerFd == -1)
	{
		printf("socket error!\n");
		return -1;
	}
	
	/* 2、对服务器端进行绑定 */
	/* 2.1 设置服务器端的socket地址描述结构体 */
	tSocketServerAddr.sin_family      = AF_INET;			// 网络协议是ipv4
	tSocketServerAddr.sin_port        = htons(SOCKET_PORT);	// socket的端口号
	tSocketServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);	// 客服端的地址可以是任意的
	memset(tSocketServerAddr.sin_zero, 0, 8);

	iSockAddrLen = sizeof(struct sockaddr);	// 获得这个结构体的大小

	/* 2.2 绑定 */
	iRet = bind(iSocketServerFd, (const struct sockaddr *)&tSocketServerAddr, iSockAddrLen);
	if(iRet == -1)
	{
		printf("bind error!\n");
		return -1;
	}

	/* 3、服务器端进行监听 */
	iRet = listen(iSocketServerFd, LISTEN_BACKLOG);
	if(iRet == -1)
	{
		printf("listen error!\n");
		return -1;
	}

	while(1)
	{
		/* 4、接收一个客服端的socket的连接 */
		iSocketClientFd = accept(iSocketServerFd, (struct sockaddr *)&tSocketClientAddr, &iSockAddrLen);
		if(iSocketClientFd < 0)
		{
			printf("accept error!\n");
			return -1;
		}

		client_flag = client_flag + 1;	// 更新标志位

		/* 连接成功,打印出客服端的ip地址 */
		printf("client %d : %s has connected\n", client_flag, inet_ntoa(tSocketClientAddr.sin_addr));

		if(fork() == 0)		/*创建子进程*/
		{
			while(1)
			{	
				/* 接收从客服端传送过来的数据 */
				iRecvLen = recv(iSocketClientFd, ucRecvBuf, ARRAY_LENGTH, 0);
				if(iRecvLen <= 0)
				{
					close(iSocketClientFd);
					return -1;
				}
				else
				{
					ucRecvBuf[iRecvLen] = '\0';
					printf("client %d : %s", client_flag, ucRecvBuf);
				}
			}
		}
	}

	close(iSocketServerFd);
	return 0;
}

二、客服端的实现

1、打开一个socket设备,获得设备描述符,指定网络协议和传输类型

/* 1、获得客服端的socket文件描述符 */
iSocketClientFd = socket(AF_INET, SOCK_STREAM, 0);	// 网络协议是ipv4,传输类型为tcp
if(iSocketClientFd == -1)
{
	printf("socket error!\n");
	return -1;
}
2、connect

将客服端和服务器端连接起来。

/* 2、初始化一个客服端和服务器之间的连接 */
/* 2.1 设置所连接的服务器 */
tSocketServerAddr.sin_family      = AF_INET;			// 协议是ipv4
tSocketServerAddr.sin_port        = htons(SOCKET_PORT);	// 绑定的端口
iRet = inet_aton(argv[1], &tSocketServerAddr.sin_addr);	// 获得的ip地址
if(iRet == 0)
{
	printf("server ip is not valid!\n");
	return -1;
}
memset(tSocketServerAddr.sin_zero, 0, 8);

iSockAddrLen = sizeof(struct sockaddr);		

/* 2.2 将客服端和服务器进行连接 */
iRet = connect(iSocketClientFd, (const struct sockaddr *)&tSocketServerAddr, iSockAddrLen);
if(iRet == -1)
{
	printf("connect error!\n");
	return -1;
}
3、接收和发送数据

if(fgets(ucSendBuf, ARRAY_LENGTH, stdin))	// 从用户输入获得一个字符串
{	
	/* 向客服端发送用户输入的信息 */
	iSendLen = send(iSocketClientFd, ucSendBuf, strlen(ucSendBuf), 0);
	if(iSendLen <= 0)
	{
		printf("send error!\n");
		close(iSocketClientFd);
		return -1;
	}
}
客服端的完整实现代码如下:
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SOCKET_PORT	1234	// 定义socket端口,用于可服务器端进行绑定
#define ARRAY_LENGTH	256		// 发送缓冲区的大小

int main(int argc, char **argv)
{
	int iSocketClientFd; 	// 定义一个客服端的socket文件描述符

	struct sockaddr_in tSocketServerAddr;	// 定义一个服务器端的socket地址描述结构体变量

	int iSockAddrLen;
	int iSendLen;
	unsigned char ucSendBuf[ARRAY_LENGTH];	// 定义缓冲区
	int iRet;

	if(argc != 2)
	{
		printf("Usage :\n");
		printf("%s <server_ip>\n", argv[0]);
		return -1;
	}

	/* 1、获得客服端的socket文件描述符 */
	iSocketClientFd = socket(AF_INET, SOCK_STREAM, 0);	// 网络协议是ipv4,传输类型为tcp
	if(iSocketClientFd == -1)
	{
		printf("socket error!\n");
		return -1;
	}

	/* 2、初始化一个客服端和服务器之间的连接 */
	/* 2.1 设置所连接的服务器 */
	tSocketServerAddr.sin_family      = AF_INET;			// 协议是ipv4
	tSocketServerAddr.sin_port        = htons(SOCKET_PORT);	// 绑定的端口
	iRet = inet_aton(argv[1], &tSocketServerAddr.sin_addr);	// 获得的ip地址
	if(iRet == 0)
	{
		printf("server ip is not valid!\n");
		return -1;
	}
	memset(tSocketServerAddr.sin_zero, 0, 8);

	iSockAddrLen = sizeof(struct sockaddr);		

	/* 2.2 将客服端和服务器进行连接 */
	iRet = connect(iSocketClientFd, (const struct sockaddr *)&tSocketServerAddr, iSockAddrLen);
	if(iRet == -1)
	{
		printf("connect error!\n");
		return -1;
	}

	printf("Input a message to %s: \n", argv[1]);
	while(1)
	{
		if(fgets(ucSendBuf, ARRAY_LENGTH, stdin))	// 从用户输入获得一个字符串
		{	
			/* 向客服端发送用户输入的信息 */
			iSendLen = send(iSocketClientFd, ucSendBuf, strlen(ucSendBuf), 0);
			if(iSendLen <= 0)
			{
				printf("send error!\n");
				close(iSocketClientFd);
				return -1;
			}
		}
	}

	close(iSocketClientFd);
	return 0;
}

三、测试
由于本实例涉及到客服端和服务器,所以需要分别运行。可以在同一台电脑上进行测试,通过不同的终端来实现;也可以在不同的电脑上进行测试,只要在同一个局域网中即可。本次测试使用第一种方式进行。

测试结果如下:

客服端:


服务器端:



通过上面测试结果可以看出,每当在客服端输入一串字符串时,在相应的服务器端也会有同样的输出。



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值