一个简单的C/S 架构程序

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

// 通过命令行参数传入绑定端口号
int main(int argc, char *argv[])
{
	if (argc < 2)
	{
		fprintf(stderr, "Usage: %s <port>.\n", argv[0]);
		return 0;
	}

	// 1. 创建socket
	// socket 第一个参数:域,本地通信(PF_UNIX, PF_LOCAL, PF_FILE, 
	// 		AF_UNIX, AF_LOCAL, AF_FILE); 网络通信(PF_INET, PF_INET6, 
	//		AF_INET, AF_INET6);
	// 第二个参数:通信类型, SOCK_STREAM, SOCK_DGRAM
	// 第三个参数:已经废弃
	int sock_fd = socket(PF_INET, SOCK_STREAM, 0);
	if (sock_fd == -1)
	{
		perror("create socket is failed");
		return -1;
	}

	// 2. 绑定主机地址
	// man in.h
	// struct sockaddr_in
	//	{
	//		sa_family_t		sin_family;	// AF_INET
	//		in_port_t		sin_port;	// Port
	//		struct in_addr	sin_addr;	// IP Address
	//	};
	// struct in_addr { in_addr_t s_addr };
	struct sockaddr_in addrServer;
	memset(&addrServer, 0, sizeof(addrServer));
	addrServer.sin_family = PF_INET;
	addrServer.sin_addr.s_addr = htonl(INADDR_ANY);
	addrServer.sin_port = htons(atoi(argv[1]));

	// 绑定
	if (bind(sock_fd, (const struct sockaddr *)&addrServer, 
		sizeof(addrServer)) == -1)
	{
		perror("bind socket is failed");
		close(sock_fd), sock_fd = -1;
		return -2;
	}

	// 3. 监听
	listen(sock_fd, 5);

	// 4. 阻塞等待客户端连接
	while (1)
	{
		struct sockaddr_in addrClient;
		memset(&addrClient, 0, sizeof(addrClient));
		socklen_t addrLength = sizeof(addrClient);
		int sock_fd_conn = 0;
		sock_fd_conn = accept(sock_fd, (struct sockaddr *)&addrClient, 
			&addrLength);
		if (sock_fd_conn == -1)
			continue;

		printf("client connected: %s\n", inet_ntoa(addrClient.sin_addr));
		char strRecv[256] = {0};
		if (recv(sock_fd_conn, strRecv, 256, 0) == -1)
		{
			fprintf(stderr, "recv is failed.\n");
			close(sock_fd_conn), sock_fd_conn = -1;
			continue;
		}

		printf("Client: %s\n", strRecv);
		char strSend[256] = {0};
		sprintf(strSend, "Hello, Client: %s\n", 
			inet_ntoa(addrClient.sin_addr));
		if (send(sock_fd_conn, strSend, 
			strlen(strSend) + sizeof(char), 0) == -1)
		{
			fprintf(stderr, "send is filed.\n");
			close(sock_fd_conn), sock_fd_conn = -1;
			continue;
		}

		// 关闭连接fd
		close(sock_fd_conn), sock_fd_conn = -1;
	}

	// 5. 关闭socket
	close(sock_fd), sock_fd = -1;
	return 0;
}

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

int main(int argc, char *argv[])
{
	if (argc < 3)
	{
		fprintf(stderr, "Usage: %s <IPAddress> <Port>", argv[0]);
		return 0;
	}

	// 1. 创建socket
	int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (sock_fd == -1)
	{
		perror("create socket fail");
		return -1;
	}

	// 2. 准备服务器地址
	struct sockaddr_in addrServer;
	memset(&addrServer, 0, sizeof(addrServer));
	addrServer.sin_family = AF_INET;
	addrServer.sin_port   = htons(atoi(argv[2]));
	inet_aton(argv[1], &addrServer.sin_addr);

	// 3. 连接到服务器
	int nRet = 0;
	nRet = connect(sock_fd, (struct sockaddr *)&addrServer, 
		sizeof(addrServer));
	if (nRet == -1)
	{
		perror("connect fail");
		close(sock_fd), sock_fd = -1;
		return -2;
	}

	// 收发数据
	const char *strSendData = "Hello, Server";
	send(sock_fd, strSendData, strlen(strSendData) + 1, 0);
	char strRecvData[256] = {0};
	recv(sock_fd, strRecvData, 256, 0);
	fprintf(stdout, "Server: %s\n", strRecvData);

	// 关闭连接fd
	close(sock_fd), sock_fd = -1;
	return 0;
}

两个文件各自编译:

gcc server.c -o server -Wall

gcc client.c -o client -Wall


先运行./server 8888

再运行./client 127.0.0.1 8888


8888 是约定端口号必须对应一致,可以为其它无符号整形。


server 端的运行结果:

[SuYH@localhost server]$ ./server 8888

client connected:127.0.0.1

Client: Hello, Server


client 端的运行结果:

[SuYH@localhost client]$ ./client 127.0.0.1 8888

Server: Hello, Client: 127.0.0.1


[SuYH@localhostclient]$ 







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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值