简单TCP编程

1.TCP服务端

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

#define SERV_PORT 5001

//本机合法IP地址
#define SERV_IP "192.168.9.30 "


int main()
{
	//1.创建流式套接字
	int listenFd = socket( AF_INET, SOCK_STREAM, 0);
	if( listenFd < 0 ){
		perror("socket error");
		exit(1);
	}
	printf( "socket ok!\n" );
	
	//2.绑定本机IP地址和端口号
	struct sockaddr_in sin;
	memset( &sin, 0, sizeof(sin) );
	
	sin.sin_family = AF_INET;
	sin.sin_port = htons(SERV_PORT);
	sin.sin_addr.s_addr = inet_addr(SERV_IP);
	
	int ret = bind(listenFd, (struct sockaddr *)&sin, sizeof(sin) );
	if( ret < 0 ){
		perror( "bind" );
		exit(1);
	}
	printf("bind ok!\n");
	
	//3.设置监听套接字
	ret = listen(listenFd, 5);
	if(ret < 0){
		perror("listen");
		exit(1);
	}
	printf("listen ok!\n");
	
	//4.等待客户端连接
	int connFd = accept(listenFd, NULL, NULL );
	if(connFd < 0){
		perror("accept");
		exit(1);
	}
	printf("accept ok!\n");
	
	//5.接受/发送消息
	char buf[BUFSIZ];
	
	while(1){
		memset( buf, 0, sizeof(buf) );
		ret = recv( connFd, buf, sizeof(buf)-1, 0 );
		if( ret < 0 ){       //出错
			perror( "recv" );
			continue;
		}
		if( 0 == ret){       //对端关闭套接字
			printf("client closes the socket!\n");
			break;
		}
		printf("recv:%s\n", buf);
	}
	
	//6.关闭套接字
	close(listenFd);
	close(connFd);
	
	return 0;
}

1.1TCP服务端优化

1.等待连接加循环,修改关闭套接字

2.地址端口快速重用,不用等MSL,就可重连
	int on = 1;
	setsockopt ( listenFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );

setsockopt() 设置 SO_REUSEADDR 选项。该选项允许在 bind() 函数中使用已被其他 socket 使用的地址.

具体来说,当一个 socket 被关闭后,它所占用的端口号将会被系统保留一段时间,以确保任何可能延迟到达的数据都能够被传递完毕。

如果在这段时间内有一个新的 socket 尝试绑定到同样的端口上,就会出现 “Address already in use” 错误。

第二个参数SOL_SOCKET 指定了要设置的 socket 层面的选项,

 "socket options level""socket 选项级别" 的意思。

第三个参数 SO_REUSEADDR 指定了要设置的选项名称,
第四个参数 &on 是一个指向选项值的指针,用于设置选项的值为 1(打开选项)
最后一个参数 sizeof(on) 是选项值的大小。

返回值为 0,则表示操作成功;
返回值为 -1,则表示操作失败,可以使用 errno 变量来查看具体的错误信息。

3.IP地址不用改

4.显示连接的客户端的地址

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

#define SERV_PORT 5001

int main()
{
	//1.创建流式套接字
	int listenFd = socket( AF_INET, SOCK_STREAM, 0);
	if( listenFd < 0 ){
		perror("socket error");
		exit(1);
	}
	printf( "socket ok!\n" );

	//优化2:允许地址和端口号快速重用
	int on = 1;
	setsockopt( listenFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );

	//2.绑定本机IP地址和端口号
	struct sockaddr_in sin;
	memset( &sin, 0, sizeof(sin) );

	sin.sin_family = AF_INET;
	sin.sin_port = htons(SERV_PORT);

	//优化3:IP地址绑到0.0.0.0(全0监听,即本机所有网卡所有IP)
	sin.sin_addr.s_addr = htonl( INADDR_ANY );

	int ret = bind(listenFd, (struct sockaddr *)&sin, sizeof(sin) );
	if( ret < 0 ){
		perror( "bind error" );
		exit(1);
	}
	printf("bind ok!\n");

	//3.设置监听套接字
	ret = listen(listenFd, 5);
	if(ret < 0){
		perror("listen error");
		exit(1);
	}
	printf("listen ok!\n");

	//优化4:显示客户端的地址
	struct sockaddr_in cin;  //定义客户端地址结构
	socklen_t len;

	//4.等待客户端连接
	while(1){//优化1:允许多个客户端接入
		memset( &cin, 0, sizeof(cin) );
		len = sizeof(sin);

		int connFd = accept(listenFd, (struct sockaddr *)&cin, &len );
		if(connFd < 0){
			perror("accept error");
			exit(1);
		}
		printf("accept (%s:%d) ok!\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port) );

		//5.接受/发送消息
		char buf[BUFSIZ];

		while(1){
			memset( buf, 0, sizeof(buf) );
			ret = recv( connFd, buf, sizeof(buf)-1, 0 );
			if( ret < 0 ){       //出错
				perror( "recv error" );
				continue;
			}
			if( 0 == ret){       //对端关闭套接字
				printf("client closes the socket!\n");
				break;
			}
			//消息处理
			printf("message from client:%s\n", buf);

			//发送消息
			printf("server send message:");
			memset(buf, 0, sizeof(buf));
			if(fgets(buf, sizeof(buf), stdin) == NULL ){
				printf("fgets error\n");
				exit(1);
			}
			send( connFd, buf, strlen(buf), 0 );
		}
		close(connFd);
	}

	//6.关闭套接字
	close(listenFd);

	return 0;
}

2.TCP客户端

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

#define QUIT_STR "quit"

void usage( const char* s ){
	printf("\n %s serv_ip, serv_port" , s);
	printf("\n serv_ip:server ip address");
	printf("\n serv_port:server port (5000 < serv_port < 65536)");
}

int main( int argc, char* argv[] )
{
	//参数检测
	if(argc != 3){
		usage( argv[0] );
		exit(1);
	}
	int port = atoi(argv[2]);
	if(port <= 5000 || port > 65535 ){
		usage( argv[0]);
		exit(1);
	}

	//1.socket 创建流式套接字
	int sockFd = socket(AF_INET, SOCK_STREAM, 0);
	if( sockFd < 0 ){
		perror("socket error");
		exit(1);
	}
	printf("socket ok!\n");
	//2.bind(可选)一般不绑定IP地址和端口号,由操作系统自动选定
	//3.connect连接服务器
	struct sockaddr_in sin;
	memset( &sin, 0, sizeof(sin) );

	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	sin.sin_addr.s_addr = inet_addr(argv[1]);
	int ret = connect(sockFd, (struct sockaddr*)&sin, sizeof(sin) );
	if( ret < 0 ){
		perror("connect error");
		exit(1);
	}
	printf("connect ok\n");

	//4.send/recv收发消息
	char buf[BUFSIZ];

	while(1){
		printf("client send message:");
		memset(buf, 0, sizeof(buf));
		if(fgets(buf, sizeof(buf), stdin) == NULL ){
			printf("fgets error\n");
			continue;
		}
		//输入quit,客户端退出
		if( strncmp(buf, QUIT_STR, strlen(QUIT_STR)) == 0 ){
			printf("input quit, client exit!\n");
			break;
		}
		send( sockFd, buf, strlen(buf), 0);
		
		//客户端接受消息
		memset( buf, 0, sizeof(buf) );
		ret = recv( sockFd, buf, sizeof(buf)-1, 0 );
		if( ret < 0 ){       //出错
			perror( "recv error" );
			exit(1);
		}
		if( 0 == ret){       //对端关闭套接字
			printf("server closes the socket!\n");
			break;
		}
		//消息处理
		printf("message from server:%s\n", buf);
	}
	//5.close关闭套接字
	close(sockFd);

	return 0;
}

客户端和服务器实现了:
客户端发消息->服务器收消息->服务器发消息->客户端收消息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值