socket(AF_INET, SOCK_STREAM…

在尝试使用socket(AF_INET, SOCK_STREAM, IPPROTO_IP)创建套接字时遇到错误,总是返回-1。解决方案是需要在调用socket函数前先调用WSAStartup进行初始化。这是因为在Windows Socket API中,WSAStartup必须是应用程序首次调用的函数,它用于指定所需的Windows Sockets版本并获取实现细节。" 127902354,14915408,Java毕业设计:二手图书回收销售系统Mybatis实现,"['Java', 'Mybatis', '数据库设计', 'Web开发', '毕业设计']
Issue: socket(AF_INET, SOCK_STREAM, IPPROTO_IP);   总是返回-1
Code: (省略了头文件的引用)
int _tmain(int argc, _TCHAR* argv[])
{
    int socketId;

    socketId = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    cout<<"socketId="<<socketId<<endl;
    
    return 0;
}

Solution:添加红色代码。(注意:简单起见,这里没有对函数返回值做应有的验证。)

#include

int _tmain(int argc, _TCHAR* argv[])
{
    int socketId;
   
    WSADATA wsData;   
    WSAStartup(MAKEWORD(2,2),&wsData);  
    
    socketId = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    cout<<"socketId="<<socketId<<endl;

    return 0;
}

调Windows Socket相关函数时,要先调 WSAStartup  ,该函数会做些准备工作。

" The WSAStartup function must be the first Windows Sockets function called by an application or DLL. It allows an application or DLL to specify the version of Windows Sockets required and retrieve details of the specific Windows Sockets implementation. "(摘自: http://msdn.microsoft.com/en-us/library/windows/desktop/ms742213(v=vs.85).aspx



一个简单的socket网络编程例子: 服务器代码: #include #include #include #include #pragma comment(lib,"ws2_32.lib") //这句话的意思是加载ws2_32.lib这个静态库 #define NETWORK_EVENT WM_USER+100 //如果你用mfc做开发,你可以点击菜单project-〉setting-〉link-〉object/library中添加这个静态库。 //如果你用c语言,你需要通过#pragma comment(命令来连接静态库 int main(int argc, char* argv[]){ HANDLE hThread = NULL; //判断是否输入了端口号 if(argc!=3){ printf("Usage: %sPortNumber\n",argv[1]); exit(-1); } //把端口号转化成整数 short port; if((port = atoi(argv[2]))==0){ printf("端口号有误!"); exit(-1); } WSADATA wsa; //初始化套接字DLL if(WSAStartup(MAKEWORD(2,2),&wsa)!=0){ //高字节指定了次版本号,低字节指定了主版本号,两个字节加到一起,就是你想要的Winsock库的版本号了 printf("套接字初始化失败!"); exit(-1); } //创建套接字 SOCKET serverSocket; if((serverSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET){ printf("创建套接字失败!"); exit(-1); } struct sockaddr_in serverAddress; memset(&serverAddress,0,sizeof(sockaddr_in)); serverAddress.sin_family=AF_INET; serverAddress.sin_addr.S_un.S_addr = htonl(INADDR_ANY); serverAddress.sin_port = htons(port); //绑定 if(bind(serverSocket,(sockaddr*)&serverAddress,sizeof(serverAddress))==SOCKET_ERROR){ printf("套接字绑定到端口失败!端口: %d\n",port); exit(-1); } //进入侦听状态 if(listen(serverSocket,SOMAXCONN)==SOCKET_ERROR){ printf("侦听失败!"); exit(-1); } printf("Server %d is listening......\n",port); SOCKET clientSocket[5],maxSocket;//用来和客户端通信的套接字 struct sockaddr_in clientAddress;//用来和客户端通信的套接字地址 memset(&clientAddress,0,sizeof(clientAddress)); int addrlen = sizeof(clientAddress); fd_set fd_read; int i=0; int j; char buf[4096]; char buff[4096]="exit"; while(1) { FD_ZERO(&fd_read); maxSocket=serverSocket; FD_SET(serverSocket,&fd_read); //FD_SET(clientSocket[i-1],&fd_read); for(j=0;j<i;j++) { FD_SET(clientSocket[j],&fd_read); if(maxSocket"); //gets(buff); if(select(maxSocket+1,&fd_read,NULL,NULL,NULL)>0) { if(FD_ISSET(serverSocket,&fd_read)) { if(buff=="") { if((clientSocket[i++]=accept(serverSocket,(sockaddr*)&clientAddress,&addrlen))==INVALID_SOCKET) { printf("接受客户端连接失败!"); exit(-1); } else { for(j=0;j5) { printf("超过最大客户端数"); exit(-1); } } else { int bytes; for(int k=0;k<i;k++) { if(FD_ISSET(clientSocket[k],&fd_read)) { bytes=recv(clientSocket[k],buf,sizeof(buf),0); if(bytes==-1) { //listen(serverSocket,SOMAXCONN); for (int l=k;l<i;l++) clientSocket[l]=clientSocket[l+1]; i--; } /*if(bytes==0) { //printf("fdsdf"); listen(serverSocket,SOMAXCONN); for (int l=k;l0) { buf[bytes]='\0'; printf("Message from %s: %s\n",inet_ntoa(clientAddress.sin_addr),buf); if(send(clientSocket[k],buf,bytes,0)==SOCKET_ERROR) { printf("发送数据失败!"); exit(-1); } } } } } } } //清理套接字占用的资源 WSACleanup(); return 0; } 客户端代码: #include #include #include #pragma comment(lib,"ws2_32.lib") int main(int argc, char* argv[]){ //判断是否输入了IP地址和端口号 if(argc!=4){ printf("Usage: %s IPAddress PortNumber\n",argv[1]); exit(-1); } //把字符串的IP地址转化为u_long unsigned long ip; if((ip=inet_addr(argv[2]))==INADDR_NONE){ printf("不合法的IP地址:%s",argv[1]); exit(-1); } //把端口号转化成整数 short port; if((port = atoi(argv[3]))==0){ printf("端口号有误!"); exit(-1); } printf("Connecting to %s:%d......\n",inet_ntoa(*(in_addr*)&ip),port); WSADATA wsa; //初始化套接字DLL if(WSAStartup(MAKEWORD(2,2),&wsa)!=0){ printf("套接字初始化失败!"); exit(-1); } //创建套接字 SOCKET sock,serverSocket; if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET){ printf("创建套接字失败!"); exit(-1); } struct sockaddr_in serverAddress; memset(&serverAddress,0,sizeof(sockaddr_in)); serverAddress.sin_family=AF_INET; serverAddress.sin_addr.S_un.S_addr = ip; serverAddress.sin_port = htons(port); //建立和服务器的连接 if(connect(sock,(sockaddr*)&serverAddress,sizeof(serverAddress))==SOCKET_ERROR) { printf("建立连接失败!"); exit(-1); } char buf[4096]; while(1){ printf(">"); //从控制台读取一行数据 gets(buf); if(send(sock,buf,strlen(buf),0)==SOCKET_ERROR){ printf("发送c数据失败!"); exit(-1); } int bytes; if((bytes=recv(sock,buf,sizeof(buf),0))==SOCKET_ERROR) { printf("接收c数据失败!\n"); exit(-1); } else { buf[bytes]='\0'; printf("Message from %s: %s\n",inet_ntoa(serverAddress.sin_addr),buf); } } //清理套接字占用的资源 WSACleanup(); return 0; }
<think>我们正在讨论的是socket编程中的socket(AF_INET, SOCK_STREAM, 0)函数调用。根据引用内容,我们可以详细解释这个函数调用的各个方面。 引用[1]和[4]都提到AF_INET表示IPv4地址族,SOCK_STREAM表示流式套接字(即TCP套接字)。 引用[2]详细解释了该函数调用的含义:创建一个IPv4地址族的流式套接字,使用默认协议(对于SOCK_STREAM,默认是TCP协议)。 引用[3]强调了在Python中应该使用常量(socket.AF_INETsocket.SOCK_STREAM)而不是数字(如2和1)来增强代码可读性。 因此,我们可以从以下几个方面进行详细解释: 1. 功能:创建一个使用IPv4和TCP协议的套接字。 2. 参数解释: - 第一个参数:地址族(Address Family),AF_INET表示IPv4。 - 第二个参数:套接字类型(Socket Type),SOCK_STREAM表示面向连接的流式套接字(TCP)。 - 第三个参数:协议(Protocol),0表示使用默认协议,即根据前两个参数自动选择(这里就是TCP)。 3. 返回值:成功时返回一个套接字描述符(非负整数),失败时返回-1(在不同编程语言中可能以异常形式表现,如Python会抛出异常)。 4. 使用说明:通常用于创建TCP服务器的监听套接字或TCP客户端的连接套接字。 另外,我们可以补充一些关于TCP套接字特性的说明(来自引用[4]): - 可靠:数据能够正确到达,如果丢失会重传。 - 面向连接:通信前需要建立连接(三次握手)。 - 流式传输:数据没有记录边界,是字节流。 我们还可以给出一个简单的使用示例(以C语言为例,因为引用[2]是C语言,但注意用户提到的是Python,所以我们也给出Python示例)。 注意:由于用户上一次的问题是关于pthread_t的,但当前的引用内容都是关于socket的,所以我们只围绕socket问题回答,不涉及线程。 最后,按照要求生成相关问题。 </think>### `socket(AF_INET, SOCK_STREAM, 0)` 详细解析 `socket(AF_INET, SOCK_STREAM, 0)` 是创建网络套接字的核心函数调用,用于建立可靠的TCP通信连接[^2][^4]。以下是详细解析: #### 1. **参数功能分解** | 参数 | 常量 | 功能描述 | 取值说明 | |------|------|----------|----------| | **AF_INET** | 地址族常量 | 指定IPv4网络协议 | 替代数字值`2`(推荐使用常量)[^3] | | **SOCK_STREAM** | 套接字类型 | 创建面向连接的流式套接字 | 提供可靠、有序的双向字节流传输[^4] | | **0** | 协议标识 | 使用默认传输协议 | 系统自动选择TCP协议(等同于`IPPROTO_TCP`)[^2] | #### 2. **核心特性** - **可靠性**:保证数据包顺序传输,自动重传丢失数据包[^4] - **连接导向**:需通过三次握手建立连接后才能通信 - **流式传输**:数据作为连续字节流处理,无固定消息边界 - **适用场景**:HTTP、FTP、SMTP等需要可靠传输的协议 #### 3. **工作流程** ```mermaid graph TD A[创建套接字] --> B[bind绑定端口] B --> C[listen监听连接] C --> D[accept接受请求] D --> E[recv/send数据传输] E --> F[close关闭连接] ``` #### 4. **返回值说明** - **成功**:返回非负整数的套接字描述符(文件句柄) - **失败**:返回`-1`(Unix/Linux)或`INVALID_SOCKET`(Windows) - 错误代码可通过`errno`(Unix)或`WSAGetLastError()`(Windows)获取 #### 5. **代码示例** **Python 实现**: ```python import socket # 创建TCP套接字 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 等同于 socket(AF_INET, SOCK_STREAM, 0)[^3] server_socket.bind(('0.0.0.0', 8080)) server_socket.listen(5) print("TCP服务器已启动...") ``` **C 语言实现**: ```c #include <sys/socket.h> int main() { // 创建TCP套接字 int sockfd = socket(AF_INET, SOCK_STREAM, 0); // [^2] if (sockfd < 0) { perror("socket创建失败"); exit(EXIT_FAILURE); } struct sockaddr_in serv_addr = {0}; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(8080); bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); listen(sockfd, 5); printf("TCP服务器已启动...\n"); } ``` #### 6. **对比无连接套接字(SOCK_DGRAM)** | 特性 | SOCK_STREAM (TCP) | SOCK_DGRAM (UDP) | |------|-------------------|------------------| | 可靠性 | 高(有确认重传) | 低(尽力交付) | | 连接 | 面向连接 | 无连接 | | 传输方式 | 字节流 | 数据报文 | | 速度 | 较慢(有握手过程) | 较快 | | 应用场景 | 文件传输、网页浏览 | 视频流、DNS查询 | #### 7. **最佳实践** 1. **错误处理**: ```c int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { fprintf(stderr, "创建失败: %s\n", strerror(errno)); return EXIT_FAILURE; } ``` 2. **资源释放**: ```python try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # ...使用套接字... finally: sock.close() # 必须显式关闭[^1] ``` 3. **端口复用**(服务器端): ```c int opt = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值