Linux网络编程--TCP的套接字通信学习笔记

TCP关于套接字socket通信涉及服务端和客户端两端的程序编写,如下:

A.  TCP_server端;

1. 创建套接字socket

2.设置服务端ip并与socket进行绑定

3.设置服务端允许的最大连接数

3.服务器处于等待阻塞状态,等待来自客户端的连接

4.等待客户端的到来并连接成功,进行数据收发

5.关闭服务端

B.  TCP_client

1.创建客户端套接字socket

2.设置需要访问的服务端ip项

3.连接服务端

4.连接成功进行数据收发

5.关闭客户端

inux网络编程是通过socket(套接字)实现的,socket是一种文件描述符。

Socket有三种类型:

      流失套接字(SOCK_STREAM): 它可以提供可靠的、面向连接的通讯流;它使用TCP协议;TCP协议保证数据传输的正确性和顺序性。

      数据套接字(SOCK_DGRAM):它定义了一种无连接的服务,数据通信相互独立的报文传输,是无序的,并且不保证可靠、无差错,他使用数据报文协议UDP。

      原始套接字(SOCK_RAW):原始套接字使用IP协议,主要用于新网络协议的测试。

网络地址:

      Socket网络程序设计中,struct sockaddr用于记录网络地址。

      struct sockaddr

      {

           u_short sa_family;  //协议簇,用于区分该网络地址属于那个协议,如IP

           char sa_data[14];  //记录地址的数据

      }

同理,也有用的多的另一种记录网络地址的数据结构体sockaddr_in:

Structsockaddr_in

{

      short int sin_family;         //同上,协议族

      unsigned short int sin_port;        //端口号

      struct in_addr sin_addr;         //协议特定地址

      unsigned char sin_zero[8];     //无效位,填0

}

typedefstruct in_addr

{

      union

      {

           struct

           {

                 unsigned chars_b1,s_b2,s_b3,s_b4;

           }S_un_b;

           struct

           {

                 unsigned short s_w1,s_w2;

           }S_un_w;

           unsignedlong s_addr;         //32位bit记录IP

      }S_un;

}IN_ADDR;

IP地址的转换:

      IP地址通常有数字加点的形式(172.15.5.20)表示和用struct in_addr中使用32位的整型数据表示,这两种形式之间的转换有以下两个函数实现:

      int inet_aton(const char *cp,structin_addr *inp);

      char * inet_ntoa(struct in_addr in);

如上:  a 表示字符串形式的ip  n表示32位整型数据的IP

网络中的传输数据统一采用大端模式(big endian)传输。

字节序转换:

      htons:把unsignedshort的主机序转换为网络序

      htonl:把unsignedlong的主机序转换为网络序

      ntohs:把unsignedshort的网络序转换为主机序

      ntohl:把unsignedlong的网络序转换为主机序

IP与主机名:

      在网络中标识一台主机可以用IP,也可以用主机名;例如本地主机可以用IP,也可以用主机名localhost来表示

      下面这个函数就是提供主机名,获取IP:

      struct hostent * gethostbyname(const char*hostname);

      struct hostent

      {

           char * h_name;           //主机的正式名字

           char * h_aliases;       //主机的别名

           int h_addrtype;        //主机的的类型

           int h_length;            //主机的地址长度

           char **h_addr_list;      //主机的IP地址列表

      }

#defineh_addr h_addr_list[0];           //定义的主机的第一个IP地址

Socket编程函数:

      socket--------------创建一个socket

      int socket(int domain, int type, intprotocol)

      domain指明所使用的协议族,通常为AF_INET,表示互联网协议族(TCP/IP协议族);type参数指定socket类型:SOCK_STREAM、SOCK_DGRAM、SOCK_RAW;protocol通常复制为0,该函数返回一个socket描述符,调用该函数将建立一个socket,失败返回-1,其实质分配一个socket数据结构。

      bind ---------------绑定IP和端口号到socket

#include<sys/socket.h>

intbind(int socketfd, struct sockaddr *addr, socklen_t addrlen);

      成功0  失败-1

socket通信时,该函数将socket与ip和端口号进行绑定

      connect------------用于与服务器建立连接

      listen-----设置服务器能处理的最大的连接要求

      accept---用来等待来自客户端的socket连接请求

#include<sys/types.h>  <sys/socket.h>

intaccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

返回的套接字描述符,失败为-1

      该函数将从连接请求队列中获得连接信息,创建新的套接字,斌返回该套接字的描述符,新的套接字用于服务器与客户端的连接通信,而旧的套接字仍处于监听状态15

      send---发送数据

      recv---接收数据

#include<string.h>

voidbzero((void *)s,int n);      //将数据s的前n个字节置位0

下面分别是服务端和客户端的代码:

//TCP text,this is a TCP server
#include <stdio.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>

#define portnumber 3333

int main()
{
	struct sockaddr_in TCP_server,TCP_client;
	int socketfd,newfd;
	int buffer[1024],tbyte;
	if((socketfd = socket(AF_INET,SOCK_STREAM,0)) == -1)	
	{
		fprintf(stderr,"Get socket error! %s \n",strerror(errno));
		exit(1);
	}
	printf("set up the socket,and sockfd is %d\n",socketfd);
	
	/*write the server address*/
	bzero(&TCP_server,sizeof(struct sockaddr_in));
	TCP_server.sin_family = AF_INET;
	TCP_server.sin_port = htons(portnumber);
	TCP_server.sin_addr.s_addr = htonl(INADDR_ANY);
	/*bind ip to socket*/
	if(bind(socketfd,(struct sockaddr *)(&TCP_server),sizeof(struct sockaddr)) == -1)
	{
		printf("bind ip to socket error!\n");
		exit(1);
	}
	if(listen(socketfd,5) == -1)
	{
		printf("set the max connect error!\n");
		exit(1); 
	}
	while(1)
	{
		bzero(&TCP_client,sizeof(struct sockaddr_in));
		tbyte = sizeof(struct sockaddr_in);	
		if((newfd = accept(socketfd,(struct sockaddr*)(&TCP_client),&tbyte)) == -1)
		{
			fprintf(stderr,"TCP connect failed: %s\n",strerror(errno));
			exit(1);
		}
		printf("Get message from: %s",inet_ntoa(TCP_client.sin_addr));
		if((tbyte = read(newfd,buffer,1024)) == -1)
		{
			printf("Get message error!\n");
			exit(1);
		}
		buffer[tbyte] = '\0';
		printf("%s\n",buffer);
		memset(buffer,'\0',1024);
		close(newfd);
	}
	return 0;
}


//TCP connect,this is a TCP client 
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>

#define portnumber 3333

int main(int argc,char *argv[])
{
	int socketfd;
	struct sockaddr_in TCP_client;
	struct hostent *host=NULL;
	char buf[1024];
	if(argc != 2)
	{
		printf("input error!\n");
		exit(1);
	}	
	if((host = gethostbyname(argv[1])) == NULL)
	{
		printf("Get name error!\n");
		exit(1);
	}
	
	if((socketfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
	{
		fprintf(stderr,"Get socket error! : %s \n",strerror(errno));
		exit(1);
	}	
	
	/*complete TCP_client*/
	bzero(&TCP_client,sizeof(struct sockaddr_in));		//clear
	TCP_client.sin_family = AF_INET;
	TCP_client.sin_port = htons(portnumber);
	TCP_client.sin_addr = *((struct in_addr *)(host->h_addr));

	if(connect(socketfd,(struct sockaddr*)(&TCP_client),sizeof(struct sockaddr)) == -1)
	{
		fprintf(stderr,"connect error! : %s\n",strerror(errno));
		exit(1);
	}	 
	printf("connect successful!\nPlease input:\n");
	fgets(buf,1024,stdin);
	write(socketfd,buf,sizeof(buf));
	printf("write succed!\n");
	close(socketfd);
	exit(0);
	return 0;
}

注:学习资料参考国嵌教学视频


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅气好男人_Jack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值