本文主要是简单的实现一个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;
}
三、测试
由于本实例涉及到客服端和服务器,所以需要分别运行。可以在同一台电脑上进行测试,通过不同的终端来实现;也可以在不同的电脑上进行测试,只要在同一个局域网中即可。本次测试使用第一种方式进行。
测试结果如下:
客服端:
服务器端:
通过上面测试结果可以看出,每当在客服端输入一串字符串时,在相应的服务器端也会有同样的输出。