get node links from_socket index value
One of your examples is - 

links.new(nodes[i.from_node.name].outputs[i.from_socket.name],
          nodes[i.to_node.name].outputs[i.to_socket.name])


Do you notice that you are trying to connect an output socket to an output socket. You would want to connect the from_node.outputs to the to_node.inputs.

Also of note is that as you know the socket names are rarely unique, which is the biggest cause of trouble here, but a socket also has a property called identifier that is a unique name for the node. I don't think you can use it as an array index but by counting your way through all sockets of the node you can find the same identifier and use your count as the index. The socket identifier property was added in 2.66 if you need to watch compatibility.

Another approach to get the socket index number is with something like -

matLinks = bpy.data.materials["SomeMat"].node_tree.links
socketID = matLinks[0].from_socket.path_from_id()[-2:-1]


So path_from_id() will return something like nodes["Mix Shader"].inputs[1] as a string, you can then use array access to get the second last character.

Most nodes only have a few inputs and outputs but to properly handle groups and script nodes which could have more than 10 sockets you would want to search for the last '[' and ']' to define your string extraction.