socket

实验1

利用Socket,编写一个聊天程序

协议设计

SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

AF_INET指定地址类型

SOCK_STREAM指定服务类型为流式Socket。

IPPROTO_TCP指定协议为TCP。

使用一个服务器来监听客户端请求,客户端请求发送信息,服务器收到信息后打印出信息并回复信息到客户端,客户端收到信息也可以再次向服务器发送信息,如此循环;若客户端或者服务器发出了exit则终止聊天,关闭Socket,结束程序。

Socket编程流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A8ogvnLp-1604834786680)(081508303133673.png)]

实验过程

实验环境为windows下的dev c++编译器。

下面以客户端socket来介绍一下程序执行流程。

winsock初始化

Winsock是Windows下的网络编程接口,它是由Unix下的BSD Socket发展而来,是一个与网络协议无关的编程接口。在windows下有两个主要版本,本次实验采用winsock2。编写socket程序时,需要在头文件处引用winsock2.h头文件,且需要链接ws2_32.lib库文件。

每个Winsock程序必须使用WSAStartup载入合适的Winsock动态链接库,如果载入失败,WSAStartup将返回SOCKET_ERROR,WSAStartup函数定义如下:

int WSAStartup(
    WORD wVersionRequested,
    LPWSADATA lpWSAData
);

wVersionRequested指定需要的Winsock版本。你可以使用宏 MAKEWORD(x, y)来指定版本号,例如:WORD sockVersion = MAKEWORD(2,2);这里x代表主版本,而y代表次版本。lpWSAData是一个指向WSAData结构的指针,WSAStartup会向该结构中填充载入的Winsock动态链接库信息。

我的初始化代码如下:如果初始化失败则退出程序。(失败时返回SOCKET_ERROR(-1))

	WORD sockVersion = MAKEWORD(2,2);     
	WSADATA wsaData;  
    if(WSAStartup(sockVersion, &wsaData)!=0)  
    {  
        return 0;  
    }

创建socket

SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if(sclient == INVALID_SOCKET)
		{
			printf("invalid socket!");
			return 0;
		}

初始化socket

sockaddr_in serAddr;
		serAddr.sin_family = AF_INET; //地址
		serAddr.sin_port = htons(8888); //端口
		serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //ip地址
//127.0.0.1是本机地址,主要用于测试,即Localhost.使用回送地址发送数据
//协议软件立即返回之,不进行任何网络传输。

sockaddr_in 结构体的定义在_ip_types.h文件中可以找到

struct sockaddr_in {
	short	sin_family; 
	u_short	sin_port; 
	struct in_addr	sin_addr;
	char	sin_zero[8];
};

创建连接

使用connect函数来创建连接,函数定义如下

WINSOCK_API_LINKAGE int WSAAPI connect(
    SOCKET s,//套接字
    const struct sockaddr *name, //套接字地址
    int namelen//套接字长度
);

发送&接收

使用sendrecv函数来分别实现信息的发送与接收。定义类似于connect函数。

flags 参数一般置0;

WINSOCK_API_LINKAGE int WSAAPI send(SOCKET s,const char *buf,int len,int flags);
WINSOCK_API_LINKAGE int WSAAPI recv(SOCKET s,char *buf,int len,int flags);

关闭socket&终止winsocket

使用closesocket(SOCKET S)函数关闭套接字,并使用WSACleanup()函数解除与Socket库的绑定并且释放Socket库所占用的系统资源。

至此客户端的一次发送或者接受信息的流程就完成了,要想多次发送信息就使用循环体即可,当然要想实现同时收发信息,需要使用多线程编程,遗憾的是,我没有成功实现。

服务端的区别在于创建完socket并初始化之后需要使用bind来绑定一个本地端口,之后使用listen函数和accept函数来监听、等待请求,收到请求时accept会返回一个套接字句柄,用这个套接字实现收发信息,完毕后,一次连接结束,closesocket,所以循环的使用accept函数接受远程连接即可实现多次收发信息,由于多线程编程掌握的不好,我实现的聊天程序只能是“回合制”的,你一句我一句的形式,这个比较遗憾。

 //bind
WINSOCK_API_LINKAGE int WSAAPI bind(SOCKET s,const struct sockaddr *name,int namelen);
//accept
WINSOCK_API_LINKAGE SOCKET WSAAPI accept(SOCKET s,struct sockaddr *addr,int *addrlen);

r *name,int namelen);
//accept
WINSOCK_API_LINKAGE SOCKET WSAAPI accept(SOCKET s,struct sockaddr *addr,int *addrlen);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值