TCP网络编程及函数详解

@TCP网络编程及函数详解

server:TCP传输(面向连接的可靠传输)
socket/bind/listen/accept/send/recv 头文件
#include <sys/types.h>
#include <sys/socket.h>

1.socket
int socket(int domain, int type, int protocol);

1)domain参数:一般是AF_INET
Name Purpose Man page
AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)

2)type参数:SOCK_STREAM (TCP)、SOCK_DGRAM (DUP)

3)protocol参数:一般填0即可

RETURN VALUE:成功返回一个新的socket,错误返回-1

2.bind
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
1)sockfd参数:创建socket返回的文件句柄(即文件描述符)
2)*addr参数:绑定服务端的 struct sockaddr_in ServerAddr;
sockaddr_in结构体定义:
struct sockaddr_in {
  short int sin_family;
  unsigned short int sin_port;
struct in_addr sin_addr;
struct in_addr
{
unsigned long s_addr;
}
unsigned char sin_zero[8];
}
sin_family:一般为AF_INET
sin_port:需要监听的端口号
sin_addr:设置为INADDR_ANY表示可以和任何主机通信
sin_zero:填充作用
3)socklen_t addrlen参数:地址结构的长度,一般是sizeof(struct sockaddr)
RETURN VALUE:成功返回一个0,错误返回-1

3.listen监听
int listen(int sockfd, int backlog);
1)sockfd参数:创建socket返回的文件句柄(即文件描述符)
2)backlog参数:最多监听个数
RETURN VALUE:成功返回0,失败返回-1

4.accept建立连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
1)sockfd参数:创建socket返回的文件句柄(即文件描述符)
2)*addr参数:接收客户端的 struct sockaddr_in ClientAddr;;
3)socklen_t *addrlen参数:
一般是int addrlen=sizeof(struct sockaddr),然后取地址&addrlen
RETURN VALUE:成功返回一个非负整数,即接收套接字的文件描述符,失败返回-1

5.send发送/recv接收
1)ssize_t send(int sockfd, const void *buf, size_t len, int flags);
sockfd参数:文件描述符
buf参数: 可定义一个 char *cSendBuf[1024],用于存储发送数据
len参数: 发送数据的长度 //strlen(cSendBuf)
flags参数:一般填0即可
RETURN VALUE:成功返回发送的字节数,错误返回-1

2)ssize_t recv(int sockfd, void *buf, size_t len, int flags);
sockfd参数:文件描述符
buf参数: 可定义一个 char *cRecvBuf[1024],用于接收数据
len参数: 接收数据的长度
flags参数:一般填0即可
RETURN VALUE:成功返回接收的字节数,错误返回-1

6.IP处理函数
1)inet_aton //把ASCLL码ip转化为网络ip
int inet_aton(const char *cp, struct in_addr *inp);
返回如果地址有效,则为非零;如果无效,则为零。

2)inet_ntoa //inet_ntoa将网络IP转化为ASCLL码
char *inet_ntoa(struct in_addr in);

6.处理僵死进程
头文件 #include <signal.h>
sighandler_t signal(int signum, sighandler_t handler);
signal(SIGCHLD, SIG_IGN);

/*Server.c*/

#include <stdio.h>

//socket/bind/listen/accept/send/recv 
#include <sys/types.h>         
#include <sys/socket.h>

//inet_ntoa
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

//memset
#include <string.h>

//fork
#include <unistd.h>

//signal
#include <signal.h>

#define SERVER_PORT 5555  	//端口号
#define BACKLOG 5			//监听最多个数

int main(int argc, char *argv[])
{
	int Server_fd; 		//server 描述符
	int Client_fd; 		//client 描述符
	int Ret1,Ret2;
	int RecvLen;
	int AddrLen;
	int ClientNum = -1;
	unsigned char cRecvBuf[1024];
	struct sockaddr_in ServerAddr;		//ServerAddr:用于存放服务端IP和端口号等
	struct sockaddr_in ClientAddr;		//ClientAddr:用于存放客户端IP和端口号等
	
	//处理僵死进程函数
	signal(SIGCHLD,  SIG_IGN);
	
	//创建socket
	Server_fd = socket(AF_INET, SOCK_STREAM, 0);   //IPV4、TCP
	if(Server_fd == -1)
	{
		printf("Server_fd socket error!\n");
		return -1;
	}
	
	
	bzero(&ServerAddr, sizeof(struct sockaddr_in));  
	ServerAddr.sin_family 		= AF_INET;  			//IPV4
	ServerAddr.sin_port 		= htons(SERVER_PORT);   //htons():把主机字节序转化为网络字节序
	ServerAddr.sin_addr.s_addr  = htonl(INADDR_ANY);    //INADDR_ANY表示可以和任何主机通信
	//memset(ServerAddr.sin_zero, 0, 8);
	
	//绑定ServerAddr
	Ret1 = bind(Server_fd, (const struct sockaddr *)&ServerAddr, sizeof(struct sockaddr));
	if(Ret1 == -1)
	{
		printf("bind error!\n");
		return -1;
	}
	
	//监听连接
	Ret2 = listen(Server_fd, BACKLOG); //BACKLOG监听最多个数
	if(Ret2 == -1)
	{
		printf("bind error!\n");
		return -1;
	}
	
	//等待并接收连接
	while(1)
	{
		printf("Waiting......\n");
		AddrLen = sizeof(struct sockaddr);
		//accept返回一个socket
		Client_fd = accept(Server_fd, (struct sockaddr *)&ClientAddr, &AddrLen);
		if(Client_fd != -1)  //表示连接成功
		{
			ClientNum ++;
			//inet_ntoa将网络IP转化为ASCLL码
			printf("Get connet from client %d: %s!\n", ClientNum, inet_ntoa(ClientAddr.sin_addr));
			
			if(fork() == 0)  //子进程
			{
				while(1)
				{
					//接收客户端数据保存到cRecvBuf并打印输出,Client_fd-->cRecvBuf
					RecvLen = recv(Client_fd, cRecvBuf, 1023, 0);
					if(RecvLen <= 0)
					{
						printf("recv ClientData failed!\n");
						close(Client_fd);
						return -1;
					}
					else
					{
						cRecvBuf[RecvLen] = '\0';   //结束标志
						printf("Get Msg from Client %d:%s\n", ClientNum, cRecvBuf);
					}
				}
			}
			// else    //主进程(父进程)
			// {
				
			// }
			
		}		
	}
		
	close(Server_fd);
	return 0;
}

/*client.c*/

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

#define SERVER_PORT 5555  	//端口号

int main(int argc, char *argv[])
{
	int Client_fd; 		//client 描述符
	int Ret;
	struct sockaddr_in ServerAddr;  
	unsigned char cSendBuf[1024]; //发送缓冲区
	int SendLen;
	
	if(argc != 2)
	{
		printf("%s :please input <server_ip>!\n", argv[1]);
		return -1;
	}
		
	//创建socket
	Client_fd = socket(AF_INET, SOCK_STREAM, 0);   //IPV4、TCP	
	if(Client_fd == -1)
	{
		printf("Client_fd socket error!\n");
		return -1;
	}
	
		
	bzero(&ServerAddr, sizeof(struct sockaddr_in));  
	ServerAddr.sin_family 		= AF_INET;  			//IPV4
	ServerAddr.sin_port 		= htons(SERVER_PORT);   //htons():把主机字节序转化为网络字节序
	//ServerAddr.sin_addr.s_addr  = htonl(INADDR_ANY);  //INADDR_ANY表示可以和任何主机通信
	if(inet_aton(argv[1], &ServerAddr.sin_addr) == 0)	//把argv[1]的ASCLL码ip转化为网络ip
	{
		printf("invalid server_ip!\n");
		return -1;
	}
	//memset(ServerAddr.sin_zero, 0, 8);

	Ret = connect(Client_fd, (const struct sockaddr *)&ServerAddr, sizeof(struct sockaddr));
	if(Ret == -1)
	{
		printf("connet error!\n");
		return -1;
	}
	
	while(1)
	{
		if(fgets(cSendBuf, 1023, stdin))   //从标准输入获取数据并发送到
		{
			//通过Client_fd发送给服务端,cSendBuf-->Client_fd
			SendLen = send(Client_fd, cSendBuf, strlen(cSendBuf), 0);
			if(SendLen <= 0)
			{
				printf("client senddata failed!\n");
				close(Client_fd);
				return -1;
			}			
		}		
	}
	close(Client_fd);	
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值