网络编程之Socket

Socket编程步骤:
在这里插入图片描述
在这里插入图片描述
服务器端编程的步骤:

  1. 加载套接字库,创建套接字(WSAStartup()/socket());
  2. 绑定套接字到一个IP地址和一个端口上(bind());
  3. 将套接字设置为监听模式等待连接请求(listen());
  4. 请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());
  5. 用返回的套接字和客户端进行通信(send()/recv());
  6. 返回,等待另一连接请求;
  7. 关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。

客户端编程的步骤:

  1. 加载套接字库,创建套接字(WSAStartup()/socket());
  2. 向服务器发出连接请求(connect());
  3. 和服务器端进行通信(send()/recv());
  4. 关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。

Socket的API:

1.socket:创建套接字

int socket(int domain, int type, int protocol);
  • domain:指明所使用的协议族,通常为AF_INET,表示互联网协议族(TCP/IP协议族):
  1. AF_INET IPv4因特网域
  2. AF_INET6 IPv6因特网域
  3. AF_UNIX Unix域
  4. AF_ROUTE 路由套接字
  5. AF_KEY 密钥套接字
  6. AF_UNSPEC 未指定
  • type:指明Socket的使用类型:
  1. SOCK_STREAM:使用套接字提供可靠的、面向连接的通信流;它使用TCP协议,从而保证数据传输的正确性和高效性
  2. SOCK_DGRAM:数据报套接字定义了一种无连接的服,数据通过相互连接的报文进行传输,是无序的,并且不保证是可靠,无差错的。它使用数据报协议UDP
  3. SOCK_RAW:允许程序使用低层协议,原始套接字允许对底层协议如IP或ICMP进行直接访问,功能强大但使用不便,主要用于一些协议的开发
  • protocol:通常赋值为0(表示默认)
  1. IPPROTE_TCP TCP传输协议
  2. IPPROTE_UDP UDP传输协议
  3. IPPROTE_SCTP SCTP传输协议
  4. IPPROTE_TIPC TIPC传输协议

2.bind:IP端口号与相应描述字赋值:

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

bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。

  • sockfd 表示socket函数创建的通信文件描述符
  • addr 一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址
  • addrlen 表示所指定的结构体变量的大小

协议地址结构根据地址创建socket时的地址协议族的不同而不同,如ipv4对应的是:

struct sockaddr{
	unsigned short as_family;	//协议族
	char sa_data[4]				//IP+端口号
}

等价于:

struct sockaddr_in {
    sa_family_t    sin_family; 	//协议族
    in_port_t      sin_port;   	//端口号
    struct in_addr sin_addr;   	//IP地址结构体
    unsigned char sin_zero[8]  	//没有实际意义
};

3.地址转换API:

int inet_aton(const char* straddr,struct in_addr* addrp);
//把字符串形为“192.168.1.123”转为网络能识别的形式
char* inet_ntoa(struct in_addr inaddr);
//把网络格式的ip地址转为字符串的形式

4.listen函数:监听设置

int listen(int sockfd, int backlog);
  • sockfd 是一个引用SOCK_STREAM或者是SOCK_SEQPACKET类型的描述符
  • backlog 指定了在请求队列允许的最大请求数

5.accpet函数:

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 
//返回连接connect_fd
  1. addr: 这是一个结果参数,它用来接受一个返回值,这返回值指定客户端的地址,当然这个地址是通过某个地址结构来描述的,用户应该知道这一个什么样的地址结构。如果对客户的地址不感兴趣,那么可以把这个值设置为NULL。
  2. addrlen: 它也是结果的参数,用来接受上述addr的结构的大小的,它指明addr结构所占有的字节个数。同样的,它也可以被设置为NULL。

accept默认会阻塞进程,直到有一个客户连接建立后返回,它返回的是一个新可用的套接字,这个套接字是连接套接字。

6.send/recv函数:数据收发:

ssize_t send(int s, const char* buf, int len, int flags);
//buf是待发送信息内容
//flags一般设置为0
ssize_t recv(int s, char FAR *buf, int len, int flags);
//flags一般设置为0

7.connect函数:用户机连接主机:

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

第一个参数即为客户端的socket描述字
第二参数为服务器的socket IP地址和端口号结构体指针
第三个参数为socket地址的长度
客户端通过调用connect函数来建立与TCP服务器的连接

demo1.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>

int main(){
    int s_fd;
    struct sockaddr_in sock_addr;  
    //1.socket()
    s_fd = socket(AF_INET,SOCK_STREAM,0);
    if(s_fd == -1){                                                                                                                                        
        perror("why socket failure");
        exit(-1);
    }   
    //2.bind()
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_port = htons(8888);
    inet_aton("192.168.95.130",&sock_addr.sin_addr);

    int ret = bind(s_fd,(struct sockaddr*)&sock_addr,sizeof(struct sockaddr_in)); 
    //这里因为第二个参数使用的高级参数,但是和原API的类型不同,所以要强转一下类型    
    //3.listen()
    listen(s_fd,10);
    //4.accept()
    int c_fd = accept(s_fd,NULL,NULL);
	//因为对客户端和服务器的地址不关心,所以设置为NULL
    printf("Connected!\n");
    while(1);
    return 0;
}

运行结果:
在这里插入图片描述在这里插入图片描述

服务器 demo

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

int main(){
	int s_fd,n_read;
	char buf[1024];
	struct sockaddr_in s_addr;
	struct sockaddr_in c_addr;
	memset(buf,0,sizeof(char));
	memset(&s_addr,0,sizeof(struct sockaddr_in));
	memset(&c_addr,0,sizeof(struct sockaddr_in));
	//1.socket
	s_fd = socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == -1){
		perror("socket");
		exit(-1);
	}
	//2.bind
	s_addr.sin_family = AF_INET;
	s_addr.sin_port = htons(8888);
	inet_aton("192.168.95.130",&s_addr.sin_addr);
	int ret = bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
	if(ret == -1){
		perror("bind");
		exit(-2);
	}
	//3.listen
	listen(s_fd,10);
	//4.accept
	int c_len = sizeof(struct sockaddr_in);
	int c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&c_len);
	if(c_fd == -1){
		perror("accept");
		exit(-4);
	}else{
		printf("%s connected!\n",inet_ntoa(c_addr.sin_addr));
	}
	//5.read
	n_read = read(c_fd,buf,1024);
	if(n_read == -1){
		perror("write");
		exit(-5);
	}else{
		printf("Content:%s\n",buf);
	}
	//6.write
	write(c_fd,(void *)buf,strlen(buf));
	return 0;
}

运行结果:
在这里插入图片描述
在这里插入图片描述
(暂时不清楚为什么在windows下只输入一个字符便与主机断开连接)

客户端 demo

#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

int main(){
    int c_fd;
    struct sockaddr_in c_addr;
    char buf[1024];
    
    memset(buf,0,sizeof(char));
    memset(&c_addr,0,sizeof(struct sockaddr));
    //1.socket()
    c_fd = socket(AF_INET,SOCK_STREAM,0);
    if(c_fd == -1){ 
        perror("socket");
        exit(-1);
    }   
    //2.connect()
    c_addr.sin_family = AF_INET;
    c_addr.sin_port = htons(8888);
    inet_aton("192.168.95.130",&c_addr.sin_addr);
    int ret = connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in));
    if(ret == -1){
        perror("connect");
        exit(-2);
    }

    //3.write()
    int Wtypes = write(c_fd,(void *)buf,1024);
    printf("Message has been sent!\n"); 
    //4.read()
    int n_read = read(c_fd,(void *)buf,strlen(buf));
    if(n_read == -1){
        perror("read");
        exit(-4);
    }else{
        printf("Receive new message!\n");
    }
    return 0;
} 

运行结果
在这里插入图片描述
在这里插入图片描述
命名好像反了。。。问题不大

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、连接池始终无法连接Mysql? 答:x86系统,可以安装5.34或者3.51版本的驱动;x64系统,推荐安装3.51版本的驱动。 ======================================================================= 2、为什么安装了驱动,还是无法连接Mysql数据库? 答:安装驱动后,请在连接池启动那里,修改驱动版本。比如安装的是3.51,那么就填写“3.51”;其他,请看参数说明。 ======================================================================= 3、MySql在64位下提示找不到odbc驱动问题 答:在64位机器上,如果你想要连接32位mysql ,一般会安装mysql connector/ODBC 64位,并在配置ODBC数据源测试中连接正常,但在程序连接,如ASP、asp.net、VB、Delphi 等软件访问数据库时,却提示找不到ODBC驱动。解决办法:因为你用的32位的mysql,那么你应该用32位的odbc配置管理器,而不是系统菜单默认的64位ODBC配置,请在 Windows\SysWOW64\ 下找到32位的ODBC配置工具 odbcad32.exe ,运行它,然后配置你需要的DSN。最后程序连接,测试OK。 ======================================================================= 4、连接池正确连接了,为什么还是无法查到数据? 答:因为参数填写不正确或者填写不完整,最后可能的是驱动版本这个参数填写错误; ======================================================================= 5、通信效率如何? 答:封装的是HPSocket通信组件,效率和稳定性没得说。 ======================================================================= 6、连接池除了Mysql,其他数据库能用吗? 答:常见的ACCESS、SQLITE3都是单机数据库,不支持多线程,所以采用连接池无意义。连接池Ex,支持MSSQL数据库,可以正常使用。 ======================================================================= 7、使用命令的过程中,出现BUG想砸电脑,几度怀疑人生,怎么办? 答:可以加入QQ群1013748987进行交流反馈。 ======================================================================= 8、我是小白,只想安安静静的学技术,加群能学到东西么? 答:这个要看群里老司机的表现了。 ======================================================================= 9、把服务端放在服务器上,为什么总是提示绑定失败? 答:请保证填写了正确的服务器地址和端口,保证服务器放行了指定端口。如果都正确无误,还是提示绑定失败,那么,请将地址改为本机的IP地址(右击网络邻居,查看属性,IP地址)。 ======================================================================= 10、如果数据库连接池启动成功,但是查询却失败了,怎么处理? 答:请检查数据库编码是否支持中文,在连接池启动参数那里的!编码,要与数据库编码一致! ======================================================================= 11、连接池ADO参数表如何使用? 答:参数表是为了杜绝SQL注入而设计的,整体操作流程如下: 数据库操作思路:→先绑定参数→增删改用 连接池.执行sql()命令;查询采用连接池.取记录集()命令→如果服务器返回的是连接池.取记录集(),客户端用记录集.导入()命令,导入服务器返回的数据。 ======================================================================= 12、连接池如何远程连接数据库? 答:可以通过Navicat等软件,将mysql的连接信息host改为%即可实现远程连接数据库。 ==============================================================

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值