利用socket实现简单的TCP网络程序。

在我们编写程序前,我们需要先了解TCP协议的特点。

  • 传输层协议
  • 有连接
  • 可靠传输
  • 面向字节流

在了解了TCP协议的特点后,我们就来实现一个简单的TCP网络程序。

在实现过程中,我们需要用到最重要的东西就是socket套接字。

socket:网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端就称为一个socket。socket本质是编程接     口,建立网络通信连接至少要一对端口号,在网络中,我们用IP加端口号来表示互联网中唯一一个进程,所以socket就是IP地址加上端口号。

创建

函数原型:int socket(int domain,int type,int protocol);

domain:协议域,又称协议族。常用的协议族有AF_INET、AF_INET6、AF_LOCAL等。协议族决定了socket的地址类型,在通信中必须采用对应的地址。

type:指定socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM等。流式socket(SOCK_STREAM)是一种面向连 接的socket,针对于面向连接的TCP服务,数据报式socket(SOCK_DGRAM)是一种无连接的socket,对应于无连接的UDP服务。

protocol:指定协议。常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP等,分别对应TCP传输协议,UDP传输协议和 STCP传输协议。

返回值:如果调用成功就返回新创建的套接字的描述符,如果失败就返回INVALI_SOCKET(Linux下失败返回-1)。

绑定

函数原型:int bind(SOCKET socket,const struct sockaddr* address,socklen_t address_len);

socket:是一个套接字描述符。

address:是一个sockaddr结构指针,该结构中包含了要结合的地址和端口号。

address_len:确定address缓冲区的长度。

返回值:成功返回0,否则返回SOCKET_ERROR。

接收

函数原型:int recvfrom(int socket,void buf,int len,unsigned int flags,struct socketaddr* from,socket_t* fromlen);

socket:标识一个已连接套接口的描述字。

buf:用于接收数据的缓冲区。

len:缓冲区长度。

flags:调用操作方式。一般设置为0。    

from:指向装有源地址的缓冲区。

fromlen:指向from缓冲区的长度。  

返回值:若无错误发生,返回读入的字节数。失败返回-1。

发送

函数原型:int sendto(SOCKET socket,const char FAR* buf,int size,int flags,const struct sockaddr FAR* to,int tolen);

socket:套接字。

buf:待发送数据的缓冲区。

size:缓冲区长度。

flags:调用方式标志位,一般为0,改变flags,将会改变sendto发送的形式。

addr:指向目的套接字的地址。

tolen:addr所指地址的长度。

返回值:如果成功,则返回发送的字节数,失败则返回-1。

接收连接请求

int accept(int fd,struct socketaddr* addr,socklen_t* len);

fd:套接字描述符。

addr:返回连接着的地址。

len:接收返回地址的缓冲区长度。

返回值:成功返回客户端的文件描述符,失败返回-1。

在了解了所需要用的函数后,我们就来具体实现它。

//client(客户端)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc,char* argv[])
{
	int sock = socket(AF_INET,SOCK_STREAM,0);
	if(sock<0)
		perror("sock");
	struct sockaddr_in server;
	server.sin_family=AF_INET;
	server.sin_port=htons(atoi(argv[2]));
	server.sin_addr.s_addr=inet_addr(argv[1]);
	int ret = connect(sock,(struct sockaddr*)&server,sizeof(server));
	if(ret<0)
		perror("connect");
	while(1)
	{
		char buf[1024];
		buf[0];
		printf("client : # ");
		fflush(stdout);
		ssize_t s = read(0,buf,sizeof(buf));
		if(s>0)
		{
			buf[s-1]=0;
		}
		write(sock,buf,sizeof(buf));
		if(strncmp(buf,"quit",4)==0)
			break;
		read(sock,buf,sizeof(buf));
		printf("server : $ %s\n",buf);
	}
	close(sock);
	return 0;
}

//server(服务器端)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc,char* argv[])
{
	int sock = socket(AF_INET,SOCK_STREAM,0);
	if(sock<0)
		perror("socket");
	struct sockaddr_in local;
	local.sin_family=AF_INET;
	local.sin_port=htons(atoi(argv[2]));
	local.sin_addr.s_addr=inet_addr(argv[1]);
	if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
		perror("bind");
	if(listen(sock,5)<0)
		perror("listen");
	while(1)
	{
		char buf[1024];
		buf[0]=0;
		struct sockaddr_in peer;
		socklen_t len = sizeof(peer);
		int newsock = accept(sock,(struct sockaddr*)&peer,&len);
		if(newsock<0)
			perror("accept");
		inet_ntop(AF_INET,&peer.sin_addr,buf,sizeof(buf));
		printf("get a connect,ip:%s,port:%d\n",buf,ntohs(peer.sin_port));
		while(1)
		{
			ssize_t s=read(newsock,buf,sizeof(buf));
            if(s>0)
            {
                buf[s]=0;
                printf("[%s:%d] %s\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port),buf);
            }
            else
            {
                printf("client quit\n");
                break;
            }
            write(newsock,buf,strlen(buf)+1);
		}
	}
	close(sock);
	return 0;
}

接下来我们来验证程序是否可以成功运行,我们打开两个终端。运行输入相同IP和端口号来测验。


由图我们能看到,两个终端确实连接成功了,我们使用客户端输入信息来测试。


服务器端可以收到客户端发送的信息,也可以对其内容进行回应,这就是一个简单的TCP网络程序,只要在相同局域网下的用户都可以进行连接。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值