套接字类型和协议设置

创建套接字

成功返回文件描述符,失败返回-1
int socket (int __domain, int __type, int __protocol) ;

__domain:套接字中使用的协议族信息

一般使用PF_INET(IPv4互联网协议族),其它协议族不常使用或尚未普及。另外,套接字中实际采用的最终协信息是通过socket 函数的第三个参数传递的。在指定的协议族范围内通过第一个参数决定第三个参数。

在这里插入图片描述


__type:套接字数据传输类型

1.面向连接的套接字(SOCK_STREAM)

特点:
传输过程中数据不会丢失
按序传输数据,较晚传输的数据不会先到达
套接字连接必须一一对应,发送端和接收端各有一个套接字
传输的数据不存在边界
在这里插入图片描述

2.面向消息的套接字(SOCK_DGRAM)

在这里插入图片描述


__protocol:协议的最终选择

  传递前两个参数即可创建所需套接字。所以大部分情况下可以向第三个参数传递0,除非遇到以下这种情况:
         “同一协议族中存在多个数据传输方式相同的协议”
  数据传输方式相同,但协议不同。此时需要通过第三个参数具体指定协议信息。
  下面以前面讲解的内容为基础,构建向socket函数传递的参数。首先创建满足如下要求的套接字:
         “IPv4协议族中面向连接的套接字”
  IPv4与网络地址系统相关。参数PF_INET指IPv4网络协议族, SOCK_STREAM是面向连接的数据传输。满足这2个条件的协议只有IPPROTO_TCP,因此可以如下调用socket函数创建套接字,这种套接字称为TCP套接字。

int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

  下面创建满足如下要求的套接字:
         “IPv4协议族中面向消息的套接字”
  SOCK_DGRAM指的是面向消息的数据传输方式,满足上述条件的协议只有IPPROTO_UDP。因此,可以如下调用socket函数创建套接字,这种套接字称为UDP套接字。

int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

面向连接的套接字示例:

  验证TCP套接字的如下特性:
      “传输的数据不存在边界”
  为验证这一点,需要让write函数的调用次数不同于read函数的调用次数。因此,在服务端中分多次调用write函数发送数据,客户端调用一次read函数以接收服务器端发送的全部数据。

Windows平台客户端,client.cpp

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <winsock2.h>
#include <iostream>
#include <string>
#pragma warning(disable:4996)
#pragma comment(lib,"ws2_32.lib")

using std::cout; using std::cerr; using std::endl; using std::string; using std::cin;

#define BUFFSIZE 2048
#define SERVER_IP  "127.0.0.1"  //"101.43.87.248"    // 指定服务端的IP
#define SERVER_PORT 9190            // 指定服务端的port


int main()
{

	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
		cout << "WSAStartup() error" << endl;

	SOCKET  hSocket = socket(PF_INET,SOCK_STREAM,0);
	if(hSocket == INVALID_SOCKET)
		cout << "socket() error" << endl;

	SOCKADDR_IN serv_addr;
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
	serv_addr.sin_port = htons(SERVER_PORT);

	//调用 connect 函数向服务器发送连接请求
	if (connect(hSocket, (SOCKADDR*)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR)
		cout << "connect() error" << endl;

	char message[30] = { 0 };
	if (int strLen = recv(hSocket, &message, 30, 0))
	{
		if (strLen == -1) 
		{
			cout << "recv() error" << endl;
		}
		else
		{
			message[strlen]=0;
			cout << message << endl;
		}
	}


	closesocket(hSocket);
	WSACleanup();
	cin.get();

	return 0;
}


Linux平台服务器端,server.cpp

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <sys/socket.h>
#include <sys/unistd.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <netinet/in.h>
#include <iostream>
#include <string>


using std::cout; using std::cerr; using std::endl; using std::string; using std::cin;

#define DEFAULT_PORT 9190    // 指定端口为 9190
#define LOG_BUFFSIZE 65536

int main()
{

	//调用 socket 函数创建套接字, serv_sock用于存放套接字,即ip和端口
	int serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	if (serv_sock == -1)
		cout << "Create socket error" << errno << ": " << strerror(errno) << endl;

	struct sockaddr_in serv_addr;
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //0.0.0.0
	serv_addr.sin_port = htons(DEFAULT_PORT);

	//调用 bind 函数分配ip地址和端口号
	if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
		cout << "Bind error" << errno << ": " << strerror(errno) << endl;

	//调用 listen 函数将套接字转为可接受连接状态
	if (listen(serv_sock, 5) == -1)
		cout << "Listen error" << errno << ": " << strerror(errno) << endl;

	struct sockaddr_in clnt_addr;
	socklen_t clnt_addr_size = sizeof(clnt_addr);
	//调用 accept 函数受理连接请求。如果在没有连接请求的情况下调用该函数,则不会返回,直到有连接请求为止

	int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
	if (clnt_sock == -1)
		cout << "Accept error" << errno << ": " << strerror(errno) << endl;

	char message[] = "hello world";
	write(clnt_sock, message, sizeof(message));//1
	write(clnt_sock, message, sizeof(message));//2
	close(clnt_sock);
	close(serv_sock);


	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值