文档章节

LINUX网络编程(TCP)(1 )

庸俗武士
 庸俗武士
发布于 2014/06/03 23:04
字数 1231
阅读 209
收藏 3

实现一个网络编程:

使用传输协议:TCP

主要是写一些关于socket函数的使用。

大致实现这么一个功能:

客户端 

发送1      服务器返回 Hello

发送2      服务器返回 GOOD

发送3      服务器返回 Bye  并且关闭连接。


先看客户端的程序:

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

#define LOG_MSG(format, ...)	do{fprintf(stderr, "[MessageInfo]: "format" \n", ##__VA_ARGS__);}while(0)

#define PORT_NUM	(2227)		//定义端口号。
#define BUFFSIZE	(1024)

#define	CMD_ONE			("1")
#define CMD_TWO			("2")
#define CMD_THREE		("3")

/*
**************************************
@brief	连接到指定的Server
@param(in)	host:	服务器名
@param(in)	port:	服务器端口
@return	Success: socket描述符应该(大于0)
		Failure: -1
**************************************
*/	
int32_t
jet_connect(const int8_t *host, uint16_t port)
{
	int32_t sd = -1;
	int8_t serv[NI_MAXSERV];
	struct addrinfo *ai, *res = NULL;
	struct addrinfo hints;
	
	//异常处理。
	if(host == NULL){
		goto func_end;
	}
	
	//snprintf会在最后加上一个\0,所以这里就不memset serv了。
	if(snprintf(serv, NI_MAXSERV, "%u", port) < 0){
		goto func_end;
	}
	
	(void)memset(&hints, 0x00, sizeof hints);
	//Ipv4 , Ipv6地址都可以		如果只要Ipv4那么这里填写:AF_INET, IPv6:AF_INET6
	hints.ai_family = AF_UNSPEC;	
	//TCP 为SOCK_STREAM, UDP为:SOCK_DGRAM
	hints.ai_socktype = SOCK_STREAM;
	//这里写不写都无所谓。 socket函数会根据family和sockettype自动匹配。
	hints.ai_protocol = IPPROTO_TCP;
	
	//取得服务器的addrinfo
	if(getaddrinfo(host, serv, &hints, &res) != 0){
		LOG_MSG("%s", gai_strerror(errno));
		goto func_end;
	}
	
	for(ai = res; ai != NULL; ai = ai->ai_next){
		sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
		if(sd < 0){
			continue;
		}
		
		if(connect(sd, ai->ai_addr, ai->ai_addrlen) < 0){
			//Connect失败了, 所以socket描述符关闭,因为后面不用了。
			close(sd);
			continue;
		}
		
		//成功连接上了。 不用在去循环了.
		break;
	}
	
	//上述循环是否成功 可以通过ai是否为NULL来判断。
	if(ai == NULL){
		sd = -1;
		goto func_end;
	}

func_end:
	if(res != NULL){
		freeaddrinfo(res);
	}

	return sd;
}

/*
**************************************
从stdin这里获取输入,然后发送给Server。
**************************************
*/
void
do_event(int32_t sd)
{
	int8_t *buf = NULL;
	int8_t *sendbuf;
	int8_t sendlen;

	if((buf = (int8_t *)malloc(BUFFSIZE)) == NULL){
		goto func_end;
	}
	(void)memset(buf, 0x00, BUFFSIZE);
	
	while(fgets(buf, BUFFSIZE, stdin) != NULL){
		//Check Command...
		if(strncmp(buf, CMD_ONE, strlen(CMD_ONE)) == 0){
			sendbuf = CMD_ONE;
		}else if(strncmp(buf, CMD_TWO, strlen(CMD_TWO)) == 0){
			sendbuf = CMD_TWO;
		}else if(strncmp(buf, CMD_THREE, strlen(CMD_THREE)) == 0){
			sendbuf = CMD_THREE;
		}else{
			//客户端如果可以的话,还是尽量不要将明显的错误信息送出去。
			LOG_MSG("The Command Err. Please Input 1~3");
			(void)memset(buf, 0x00, BUFFSIZE);
			continue;
		}

		sendlen = strlen(sendbuf);
		
		if(write(sd, sendbuf, sendlen) < sendlen){
			LOG_MSG("message send to server Error");
		}
		
		(void)memset(buf, 0x00, BUFFSIZE);
		if(read(sd, buf, BUFFSIZE) < 0){
			LOG_MSG("message receive from server Error");
		}
		LOG_MSG("%s", buf);
		
		if(sendbuf == (int8_t*)CMD_THREE){
			break;
		}
		
		(void)memset(buf, 0x00, BUFFSIZE);
	}
	
func_end:
	if(buf != NULL){
		free(buf);
	}
	
	return ;
}

int
main(int ac, char **av)
{
	int32_t sd;

	//需要输入Server的地址或名字。
	if(ac != 2){
		LOG_MSG("you should indicate a server");
		goto func_end;
	}

	if((sd = jet_connect(av[1],  PORT_NUM)) < 0){
		LOG_MSG("Connect to Server Failed");
		goto func_end;
	}

	do_event(sd);
	close(sd);
	
func_end:
	return 0;
}


同时给出服务器端 程序:(注释 基本没写..)

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

#define PORT_NUM	(2227)		//定义端口号。
#define BUFFSIZE	(1024)

#define	CMD_ONE			("1")
#define CMD_TWO			("2")
#define CMD_THREE		("3")

#define CMD_CODE_ERR	(0)
#define CMD_CODE_ONE	(1)
#define CMD_CODE_TWO	(2)
#define CMD_CODE_THREE	(3)

#define LISTEN_QUE		(10)

#define LOG_MSG(format, ...)	do{fprintf(stderr, "[MessageInfo]: "format" \n", ##__VA_ARGS__);}while(0)

typedef struct socklnk_st{
	int32_t sd;
	struct socklnk_st *next;
}socklnk_t;


socklnk_t*
create_soclnk(int32_t data)
{
	socklnk_t *soclnk = NULL;
	
	soclnk = (socklnk_t *)malloc(sizeof(socklnk_t));
	if(soclnk != NULL){
		soclnk->next = NULL;
		soclnk->sd = data;
	}
	
	return soclnk;
}

void
free_soclnk(socklnk_t *dst)
{
	socklnk_t *tmp = dst;
	socklnk_t *next;

	while(tmp != NULL){
		next = tmp->next;
		close(tmp->sd);
		free(tmp);
		tmp = next;
	}
}

//定义每个Code返回值。
//这个是C99下,数组初始化才可以这么使用
static int8_t *server_msg[] = {
	[CMD_CODE_ONE] = "Hello",
	[CMD_CODE_TWO] = "Good",
	[CMD_CODE_THREE] = "Bye",
	[CMD_CODE_ERR]	= "Error Command",
};

socklnk_t *
start_serice(uint16_t port)
{
	int8_t serv[NI_MAXSERV];
	int32_t sd;
	int32_t opt = 1;
	struct addrinfo *ai, *res = NULL;
	struct addrinfo hints;
	socklnk_t *head = NULL;
	socklnk_t *cur  = NULL;	
	
	if(snprintf(serv, NI_MAXSERV, "%u", port) < 0){
		goto func_end;
	}
	
	(void)memset(&hints, 0x00, sizeof hints);
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_PASSIVE;
	
	if(getaddrinfo(NULL, serv, &hints, &res) != 0){
		goto func_end;
	}
	
	for(ai = res; ai != NULL; ai = ai->ai_next){
		sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
		if(sd < 0){
			continue;
		}
		
		if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) < 0){
			close(sd);
			free_soclnk(head);
			goto func_end;
		}
		
		if(bind(sd, ai->ai_addr, ai->ai_addrlen) < 0){
			close(sd);
			continue;
		}
		
		if(listen(sd, LISTEN_QUE) < 0){
			close(sd);
			continue;
		}
		
		if(head == NULL){
			head = create_soclnk(sd);
			if(head == NULL){
				close(sd);
				free_soclnk(head);
				goto func_end;			
			}
			cur = head;
		}else{
			cur->next = create_soclnk(sd);
			if(cur->next == NULL){
				close(sd);
				free_soclnk(head);
				goto func_end;			
			}
			cur = cur->next;
		}
	}
	
func_end:
	if(res != NULL){
		freeaddrinfo(res);
	}

	return head;
}

int
main(int ac, char **av)
{
	int8_t *buf;
	int32_t connfd;
	int32_t maxfd = -1;
	int32_t cmd;
	int32_t sendlen;
	fd_set fds;
	
	socklnk_t *sdlnk = NULL;
	socklnk_t *this;
	
	
	buf = (int8_t*)malloc(BUFFSIZE);
	if(buf == NULL){
		LOG_MSG("Service Start Failed");
		goto func_end;		
	}
	
	sdlnk = start_serice(PORT_NUM);
	if(sdlnk == NULL){
		LOG_MSG("Service Start Failed");
		goto func_end;
	}
	
	//main Loop
	for(;;){
		FD_ZERO(&fds);
		for(this = sdlnk; this != NULL; this = this->next){
			FD_SET(this->sd, &fds);
			if(this->sd > maxfd){
				maxfd = this->sd;
			}
		}
		
		if(select(maxfd + 1, &fds, NULL, NULL, NULL) > 0){
			for(this = sdlnk; this != NULL; this = this->next){
				if(FD_ISSET(this->sd, &fds) != 0){
					if((connfd = accept(this->sd, NULL, NULL)) < 0){
						continue;
					}
					break;
				}
			}
		}else{
			goto func_end;
		}
	
		if(this == NULL){
			goto func_end;
		}
		
		for(;;){
			(void)memset(buf, 0x00, BUFFSIZE);
			
			if(read(connfd, buf, BUFFSIZE) > 0){
				if(strncmp(buf, CMD_ONE, strlen(CMD_ONE)) == 0){
					cmd = CMD_CODE_ONE;
				}else if(strncmp(buf, CMD_TWO, strlen(CMD_TWO)) == 0){
					cmd = CMD_CODE_TWO;
				}else if(strncmp(buf, CMD_THREE, strlen(CMD_THREE)) == 0){
					cmd = CMD_CODE_THREE;
				}else{
					cmd = CMD_CODE_ERR;
				}
				
				sendlen = strlen(server_msg[cmd]);
				
				if(write(connfd, server_msg[cmd], sendlen) != sendlen){
					close(connfd);
					goto func_end;
				}
				
				if(cmd == CMD_CODE_THREE){
					break;
				}
			}else{
				break;
			}
		}
		
		close(connfd);	
	}
	
	
	
func_end:
	if(sdlnk != NULL){
		free_soclnk(sdlnk);
	}
	
	if(buf != NULL){
		free(buf);
	}
	
	return 0;
}


现在用客户端输入1,2,3  都可以从服务器哪里接受到信息了。。

但是好像有点什么不足的样子。。

下一篇 对 服务器 端 做一个改进/。


© 著作权归作者所有

共有 人打赏支持
庸俗武士
粉丝 2
博文 15
码字总数 5935
作品 0
杭州
高级程序员
私信 提问
Linux多线程并发服务器编程(线程池,FTP服务器)

分享网盘下载:https://pan.baidu.com/s/1gfNCcXt 密码: irfk 内容简介 本课程从最基础的进程、线程概念讲起逐步深入,通过理论与实践结合的方式,使学员快说掌握linux多线程网络编程技术,并...

人气王子333
06/26
0
0
Linux网络编程:什么是Linux下的网络编程?

想知道Linux下的网络编程培训×××?先来了解一下什么是Linux下的网络编程吧!Linux下的网络编程指的是socket套接字编程,入门比较简单。在学校里学过一些皮毛,平时就是自学玩,没有见识过...

长沙千锋
05/23
0
0
给PHP扩展/C语言/网络编程初学者推荐的几本书

Linux/Unix系统 深入理解计算机系统 UNIX环境高级编程 深入理解Linux内核 网络通信编程 UNIX网络编程 TCP/IP详解 Linux多线程服务端编程 数据结构与算法 算法导论 《数据结构》(C语言版) ...

Surjur
2014/08/06
0
0
python的Socket编程基础

下面一些是python网络编程基础知识,很少在项目中直接使用,都是用的twisted,gevent,tornado等网络框架.但是学习基础知识可以弄懂socket流程. python的socket模块的网络编程步骤和linux c基本一...

flyking
2013/10/23
0
0
PHP程序员进阶之路好书籍推荐

今天给PHP程序员们推荐几本PHP进阶好书,PHP程序员们不要以为自己现在已经工作就放弃了一个上进的心,现在互联网发展这么快,小心长江后浪推前浪,前浪死在沙滩上哦。。。 · 《UNIX网络编程...

Yomut
04/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Alibaba Java诊断利器Arthas实践--使用redefine排查应用奇怪的日志来源

背景 随着应用越来越复杂,依赖越来越多,日志系统越来越混乱,有时会出现一些奇怪的日志,比如: [] [] [] No credential found 那么怎样排查这些奇怪的日志从哪里打印出来的呢?因为搞不清...

hengyunabc
22分钟前
0
0
home hosts

home hosts lwk@qwfys:~$ cat /etc/hosts127.0.0.1 localhost127.0.1.1 qwfys192.168.56.101vm600.qwfys.com39.108.212.91alpha1.ppy.com39.108.117.122alpha2.p......

qwfys
28分钟前
0
0
大数据教程(6.1)hadoop生态圈介绍及就业前景

1. HADOOP背景介绍 1.1、什么是HADOOP 1.HADOOP是apache旗下的一套开源软件平台 2.HADOOP提供的功能:利用服务器集群,根据用户的自定义业务逻辑,对海量数据进行分布式处理 3.HADOOP的核心组...

em_aaron
今天
2
0
hadoop垃圾回收站

在生产生,hdfs回收站必须是开启的,一般设置为7天。 fs.trash.interval 为垃圾回收站保留时间,如果为0则禁用回收站功能。 fs.trash.checkpoint.interval 回收站检查点时间,一般设置为小于...

hnairdb
昨天
1
0
腾讯与Github的魔幻会面背后的故事…

10月22日,腾讯开源管理办公室有幸邀请到Github新晋CEO Nat Friedman,前来鹅厂参观交流。目前腾讯已经有近70个项目在Github上开源,共获得17w stars,世界排名11位。Github是腾讯开源的主阵...

腾讯开源
昨天
12
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部