socket实现TCP通信

来源:互联网 发布:车载网络硬盘录像机 编辑:程序博客网 时间:2024/04/28 19:04

TCP是一种可靠的,面向连接的协议。

在socket中,建立TCP连接的过程大致如下:

服务器端:

1.初始化套接字

2.创建服务器socket

3.将本机地址与服务器socket绑定在一起

4.服务器开始监听

5.服务器确认请求(确认之前时一种阻塞的状态),accept()函数生成一个新的socket。

6.用新生成的socket接收数据

客户端:

1.初始化套接字

2.生成与服务器连接的socket

3.将socket与服务器进行连接

4.向服务器发送数据


以上过程需要用到以下一些函数:

1.SOCKET socket(int 地址族,int 套接字类型,int 协议类型),返回生成的SOCKET

2.int bind(SOCKET 要绑定的套接字,const sockaddr* 要绑定的地址的结构体的指针,int 第二个参数的长度)

将套接字绑定到指定的网络地址上,一般在connect()或listen()函数前调用。
在服务器端,用作监听客户端连接请求的套接字一定要经过绑定。
在客户端使用的套接字一般不必绑定,除非要指定它使用特定的网络地址。

3. int listen(SOCKET 要监听的套接字,int 最大允许等待连接长度)

适用于支持连接的套接字。仅用于服务器。

4.SOCKET accept(SOCKET 监听套接字,sockaddr* 客户端的地址结构,int* 客户端地址长度)

accept函数将从listen的等待队列中抽取出一个项,建立TCP连接,返回一个已经经过了连接的新的套接字。

若队列中没有连接请求,当:
阻塞方式时,该函数阻塞调用它的进程。
非阻塞方式时,该函数返回一个错误代码。

5.int connect(SOCKET s,const sockaddr* 服务器端地址结构,int 服务器端地址长度)

用于客户端请求向服务器端建立连接。

6.int recv(SOCKET 已建立连接的套接字,char* 接收字符串的缓冲区,int 缓冲区长度,int 选项一般为0)

返回实际接收的字节数

7.int send(SOCKET 已建立连接的套接字,char* 发送字符串的缓冲区,int 缓冲区长度,int 选项一般为0)

返回实际发送的字节数


源代码如下:

服务器端:

#include "stdafx.h"#include <iostream>#include <winsock2.h>#pragma comment(lib,"WS2_32.lib")#include <string.h>#define bufsize 64int main(){WSADATA wsd;SOCKET sServer, sClient;int retval;char recvbuf[bufsize];if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0){printf("startup failed\n");WSACleanup();return -1;}sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (sServer == INVALID_SOCKET){printf("socket failed\n");WSACleanup();return -1;}sockaddr_in addrServ;addrServ.sin_family = AF_INET;addrServ.sin_port = htons(9000);addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//INADDR_ANY是IP地址0.0.0.0,表示来自任意IP地址的请求均接收retval = bind(sServer, (sockaddr*)&addrServ, sizeof(sockaddr_in));if (retval == SOCKET_ERROR){printf("bind failed\n");WSACleanup();return -1;}retval = listen(sServer, 1);if (retval == SOCKET_ERROR){printf("listen failed\n");closesocket(sServer);WSACleanup();return -1;}printf("TCP server start...\n");//至此,服务器启动完成sockaddr_in ClientAddr;int addrlen;addrlen = sizeof(ClientAddr);sClient = accept(sServer, (sockaddr*)&ClientAddr, &addrlen);//阻塞状态if (sClient == INVALID_SOCKET){printf("accept failed\n");closesocket(sServer);WSACleanup();return -1;}printf("client has log in\n");//打开客户端时,显示客户已登录while (true){memset(recvbuf, 0, sizeof(recvbuf));retval = recv(sClient, recvbuf, BUFSIZ, 0);if (retval == SOCKET_ERROR){printf("recv failed\n");closesocket(sClient);closesocket(sServer);WSACleanup();break;}printf("ip: %s\nport: %d\ncontent: %s\n", inet_ntoa(ClientAddr.sin_addr), ClientAddr.sin_port, recvbuf);}return 0;}

客户端:

#include "stdafx.h"#include <winsock2.h>#include <string>#include <string.h>#include <iostream>#include <stdio.h>#pragma comment(lib,"WS2_32.lib")#define bufsize 64int main(){WSADATA wsd;SOCKET sHost;sockaddr_in servaddr;char buf[bufsize];int retval;if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0){printf("stratup failed\n");return -1;}sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (sHost == INVALID_SOCKET){printf("socket failed\n");WSACleanup();return -1;}servaddr.sin_family = AF_INET;servaddr.sin_addr.S_un.S_addr = inet_addr("10.21.38.14");//服务器IP地址;servaddr.sin_port = htons(9000);int addrlen;addrlen = sizeof(servaddr);retval = connect(sHost, (sockaddr*)&servaddr, addrlen);if (retval == SOCKET_ERROR){printf("connect error\n");closesocket(sHost);WSACleanup();return -1;}while (1){printf("input the message:\n");std::string str;std::getline(std::cin, str);memset(buf, 0, sizeof(buf));strcpy(buf, str.c_str());retval = send(sHost, buf, strlen(buf), 0);if (retval == SOCKET_ERROR){printf("send failed\n");closesocket(sHost);WSACleanup();return -1;}}    return 0;}

例如:



0 0